1 #ifndef lint 2 static char sccsid[] = "@(#)io.c 1.6 (Berkeley/CCI) 05/31/88"; 3 #endif 4 5 #include "vdfmt.h" 6 #include "cmd.h" 7 8 9 /* 10 ** 11 */ 12 13 static cmd_text_element nul_table[] = { 14 { 0, "", "" } 15 }; 16 17 int wait_for_char; 18 int vdtimeout; 19 char *clean_up = "Cleaning up... Please wait.\n"; 20 21 22 /* 23 ** 24 */ 25 26 poll(wait) 27 int wait; 28 { 29 register struct vddevice *addr = C_INFO->addr; 30 int tokens[10]; 31 int didmsg = 0; 32 33 wait_for_char = 0; 34 vdtimeout = wait*1000; 35 for (;;) { 36 uncache(&(dcb.operrsta)); 37 if (dcb.operrsta & (DCBS_DONE | DCBS_ABORT)) 38 break; 39 if (input()) { 40 get_text_cmd(nul_table, tokens); 41 if (didmsg == 0 && kill_processes == true) { 42 didmsg = 1; 43 indent(); 44 print(clean_up); 45 exdent(1); 46 } 47 } 48 if (vdtimeout-- <= 0) { 49 if(C_INFO->type == VDTYPE_VDDC) 50 printf("\nVDDC"); 51 else 52 printf("\nSMD-E"); 53 printf(": Controller timeout"); 54 abort: 55 VDABORT(addr, C_INFO->type); 56 DELAY(30000); 57 break; 58 } 59 DELAY(1000); 60 } 61 if ((vdtimeout > 0)) { 62 if (C_INFO->type == VDTYPE_SMDE) { 63 for (;;) { 64 uncache(&(addr->vdcsr)); 65 if ((addr->vdcsr & CS_GO) == 0) 66 break; 67 DELAY(1000); 68 if (vdtimeout-- <= 0) { 69 printf("\nSMD-E timed out clearing GO"); 70 goto abort; 71 } 72 } 73 DELAY(300); 74 } 75 DELAY(500); 76 } 77 DELAY(200); 78 if((dcb.opcode == VDOP_RD) || (dcb.opcode == VDOP_RDRAW)) 79 mtpr(PADC, 0); 80 uncache(&(dcb.operrsta)); 81 uncache(&(dcb.err_code)); 82 wait_for_char = 1; 83 } 84 85 86 /* 87 ** Access_with_no_trailer is used to perform controller functions which 88 ** require no data movement. 89 */ 90 91 access_with_no_trailer(function, wait_time) 92 int function, wait_time; 93 { 94 dcb.opcode = function; /* command */ 95 dcb.intflg = DCBINT_NONE; 96 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 97 dcb.operrsta = 0; 98 dcb.devselect = (function == VDOP_START) ? 0 : 99 ((char)cur.drive | lab->d_devflags); 100 dcb.trailcnt = (char)0; 101 mdcb.mdcb_head = &dcb; 102 mdcb.mdcb_status = 0; 103 VDGO(C_INFO->addr, (u_long)&mdcb, C_INFO->type); 104 poll(wait_time); 105 if(vdtimeout <= 0) { 106 printf(" during startup operation.\n"); 107 _longjmp(abort_environ, 1); 108 } 109 return dcb.operrsta; 110 } 111 112 vread(sn, buf, seccnt) 113 int sn, seccnt; 114 char *buf; 115 { 116 return (vrdwr(sn, buf, seccnt, VDOP_RD)); 117 } 118 119 vwrite(sn, buf, seccnt) 120 int sn, seccnt; 121 char *buf; 122 { 123 return (vrdwr(sn, buf, seccnt, VDOP_WD)); 124 } 125 126 vrdwr(sn, buf, seccnt, op) 127 int sn, seccnt, op; 128 char *buf; 129 { 130 dskadr dskaddr; 131 132 dskaddr.cylinder = sn / lab->d_secpercyl; 133 sn %= lab->d_secpercyl; 134 dskaddr.track = sn / lab->d_nsectors; 135 dskaddr.sector = sn % lab->d_nsectors; 136 if (access_dsk(buf, &dskaddr, op, seccnt, 1) & DCBS_HARD) 137 return (0); 138 return (seccnt); 139 } 140 141 /* 142 ** access_dsk is used by other routines to do reads and writes to the disk. 143 ** The status of the read / write is returned to the caller for processing. 144 */ 145 146 access_dsk(buf, dskaddr, func, count, wait) 147 char *buf; 148 dskadr *dskaddr; 149 int func, count, wait; 150 { 151 cur.daddr.cylinder = dskaddr->cylinder; 152 cur.daddr.track = dskaddr->track; 153 wait_for_char = 0; 154 dcb.opcode = func; /* format sector command */ 155 dcb.intflg = DCBINT_NONE; 156 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 157 dcb.operrsta = 0; 158 dcb.devselect = (char)cur.drive | lab->d_devflags; 159 if(func == VDOP_SEEK) { 160 dcb.trailcnt = (char)(sizeof(struct trseek) / sizeof(long)); 161 dcb.trail.sktrail.skaddr.cylinder = dskaddr->cylinder; 162 dcb.trail.sktrail.skaddr.track = dskaddr->track; 163 dcb.trail.sktrail.skaddr.sector = dskaddr->sector; 164 } else { 165 dcb.trailcnt = (char)(sizeof(struct trrw) / sizeof(long)); 166 dcb.trail.rwtrail.memadr = (u_long)buf; 167 dcb.trail.rwtrail.wcount=count*(lab->d_secsize/sizeof(short)); 168 dcb.trail.rwtrail.disk.cylinder = dskaddr->cylinder; 169 dcb.trail.rwtrail.disk.track = dskaddr->track; 170 dcb.trail.rwtrail.disk.sector = dskaddr->sector; 171 } 172 mdcb.mdcb_head = &dcb; 173 mdcb.mdcb_status = 0; 174 VDGO(C_INFO->addr, (u_long)&mdcb, C_INFO->type); 175 if(wait) { 176 poll(10); 177 if(vdtimeout <= 0) { 178 printf(" in access_dsk.\n"); 179 _longjmp(abort_environ, 1); 180 } 181 } 182 wait_for_char = 1; 183 return dcb.operrsta; 184 } 185 186 187 /* 188 ** Spin_up_drive starts the drives on a controller and waits around for 189 ** the drive to spin up if it is not already spinning. 190 */ 191 192 spin_up_drive() 193 { 194 register struct vddevice *addr = C_INFO->addr; 195 196 VDRESET(addr, C_INFO->type); 197 if(C_INFO->type == VDTYPE_SMDE) { 198 addr->vdcsr = 0; 199 addr->vdtcf_mdcb = AM_ENPDA; 200 addr->vdtcf_dcb = AM_ENPDA; 201 addr->vdtcf_trail = AM_ENPDA; 202 addr->vdtcf_data = AM_ENPDA; 203 addr->vdccf = CCF_SEN | 0x8 | CCF_STS | 204 XMD_32BIT | BSZ_16WRD | CCF_ERR | 205 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE; 206 } 207 access_with_no_trailer(VDOP_INIT, 10); 208 access_with_no_trailer(VDOP_DIAG, 20); 209 configure_drive(0); 210 } 211 212 /* 213 ** Configure_drive tells the controller what kind of drive is attached 214 ** on a particular line. 215 */ 216 217 configure_drive(pass) 218 int pass; 219 { 220 register struct vddevice *addr = C_INFO->addr; 221 register i; 222 223 top: 224 dcb.opcode = VDOP_CONFIG; /* command */ 225 dcb.intflg = DCBINT_NONE; 226 dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 227 dcb.operrsta = 0; 228 dcb.devselect = cur.drive | lab->d_devflags; 229 dcb.trail.rstrail.ncyl = lab->d_ncylinders; 230 dcb.trail.rstrail.nsurfaces = lab->d_ntracks; 231 if(C_INFO->type == VDTYPE_VDDC) 232 dcb.trailcnt = (char)2; 233 else { 234 dcb.trailcnt = sizeof (struct treset)/sizeof (long); 235 dcb.trail.rstrail.nsectors = lab->d_nsectors; 236 dcb.trail.rstrail.slip_sec = lab->d_sparespertrack; 237 dcb.trail.rstrail.recovery = VDRF_NONE; 238 addr->vdcylskew = lab->d_cylskew; 239 addr->vdtrackskew = lab->d_trackskew; 240 /* 241 addr->vdsecsize = lab->d_secsize/sizeof(short); 242 */ 243 } 244 /* 245 printf("devsel %x, ncyl %d, ntrk %d, nsec %d, slip %d, cylskew %d, trackskew %d, secsize %d\n", dcb.devselect, dcb.trail.rstrail.ncyl, dcb.trail.rstrail.nsurfaces, dcb.trail.rstrail.nsectors, dcb.trail.rstrail.slip_sec, lab->d_cylskew, lab->d_trackskew, lab->d_secsize); 246 */ 247 mdcb.mdcb_head = &dcb; 248 mdcb.mdcb_status = 0; 249 VDGO(addr, (u_long)&mdcb, C_INFO->type); 250 poll(5); 251 if(vdtimeout <= 0) { 252 printf(" during drive configuration.\n"); 253 goto bad; 254 } 255 if(dcb.operrsta & VDERR_HARD) { 256 if (C_INFO->type == VDTYPE_SMDE) { 257 if (lab->d_devflags == 0) { 258 lab->d_devflags = VD_ESDI; 259 goto top; 260 } 261 #ifdef notdef 262 printf("vdstatus %x\n", addr->vdstatus[cur.drive]); 263 if ((addr->vdstatus[cur.drive] & STA_US) == 0) { 264 printf("Drive not present\n\n"); 265 goto bad; 266 } 267 #endif 268 } 269 if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { 270 printf("drive config error\n"); 271 goto bad; 272 } 273 if(pass) { 274 printf("\nDrive failed to start!\n\n"); 275 goto bad; 276 } 277 printf("\ndrive not ready, attempting to spin up..."); 278 access_with_no_trailer(VDOP_START, 62); 279 for (i = 0; i < 620; i++) { 280 if (C_INFO->type == VDTYPE_SMDE && 281 addr->vdstatus[cur.drive] & STA_UR) 282 break; 283 DELAY(100000); 284 } 285 printf(" retrying drive configuration\n"); 286 pass++; 287 lab->d_devflags = 0; 288 goto top; 289 } 290 D_INFO->alive = u_true; 291 return; 292 bad: 293 D_INFO->alive = u_false; 294 _longjmp(abort_environ, -1); 295 } 296 297 298 /* 299 ** data_ok checks an error status word for bit patterns 300 ** associated with error conditions from the VDDC controller. If a hardware 301 ** error is present then the problem is reported on the console. 302 ** If a data error is present the a zero is returned. 303 ** If everything is OK then a 1 is returned. 304 */ 305 306 data_ok() 307 { 308 register int status = dcb.operrsta; 309 310 if(status & HARD_ERROR){ 311 vd_error("data transfer"); 312 printf(" op = 0x%x\n", dcb.opcode); 313 reset_controller(); 314 dcb.operrsta &= HEADER_ERROR; 315 } 316 return (int)(!(status & (DATA_ERROR | HEADER_ERROR))); 317 } 318 319 vd_error(s) 320 char *s; 321 { 322 register int status = dcb.operrsta; 323 324 print("error at sector %d (cyl %d trk %d sect %d),\n", 325 to_sector(cur.daddr), dcb.err_cyl & 0xfff, dcb.err_trk, 326 dcb.err_sec); 327 print(" status=%b", dcb.operrsta, VDERRBITS); 328 if (C_INFO->type == VDTYPE_SMDE) 329 printf(", ecode=0x%x", dcb.err_code); 330 printf("\n"); 331 } 332 333 334 /* 335 ** 336 */ 337 338 reset_controller() 339 { 340 printf("Resetting controller. Please wait...\n"); 341 spin_up_drive(); 342 printf("Controller was reset successfully.\n"); 343 } 344 345 /* 346 ** 347 */ 348 349 static int indent_count; 350 351 352 /* 353 ** 354 */ 355 356 indent() 357 { 358 indent_count += 2; 359 } 360 361 362 /* 363 ** 364 */ 365 366 exdent(count) 367 int count; 368 { 369 if(count == -1) 370 indent_count = 0; 371 else 372 indent_count -= count * 2; 373 if(indent_count < 0) 374 indent_count = 0; 375 } 376 377 378 /* 379 ** 380 */ 381 /*VARARGS1*/ 382 print(par0, par1, par2, par3, par4, par5, par6) 383 char *par0, *par1, *par2, *par3, *par4, *par5, *par6; 384 { 385 register int count = indent_count; 386 387 while(count--) 388 printf(" "); 389 printf(par0, par1, par2, par3, par4, par5, par6); 390 DELAY((strlen(par0) + 20) * 9000); 391 } 392