1 #ifndef lint 2 static char sccsid[] = "@(#)io.c 1.5 (Berkeley/CCI) 11/23/87"; 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 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); 245 mdcb.mdcb_head = &dcb; 246 mdcb.mdcb_status = 0; 247 VDGO(addr, (u_long)&mdcb, C_INFO->type); 248 poll(5); 249 if(vdtimeout <= 0) { 250 printf(" during drive configuration.\n"); 251 goto bad; 252 } 253 if(dcb.operrsta & VDERR_HARD) { 254 if (C_INFO->type == VDTYPE_SMDE) { 255 if (lab->d_devflags == 0) { 256 lab->d_devflags = VD_ESDI; 257 goto top; 258 } 259 #ifdef notdef 260 printf("vdstatus %x\n", addr->vdstatus[cur.drive]); 261 if ((addr->vdstatus[cur.drive] & STA_US) == 0) { 262 printf("Drive not present\n\n"); 263 goto bad; 264 } 265 #endif 266 } 267 if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) { 268 printf("drive config error\n"); 269 goto bad; 270 } 271 if(pass) { 272 printf("\nDrive failed to start!\n\n"); 273 goto bad; 274 } 275 printf("\ndrive not ready, attempting to spin up..."); 276 access_with_no_trailer(VDOP_START, 62); 277 for (i = 0; i < 620; i++) { 278 if (C_INFO->type == VDTYPE_SMDE && 279 addr->vdstatus[cur.drive] & STA_UR) 280 break; 281 DELAY(100000); 282 } 283 printf(" retrying drive configuration\n"); 284 pass++; 285 lab->d_devflags = 0; 286 goto top; 287 } 288 D_INFO->alive = u_true; 289 return; 290 bad: 291 D_INFO->alive = u_false; 292 _longjmp(abort_environ, -1); 293 } 294 295 296 /* 297 ** data_ok checks an error status word for bit patterns 298 ** associated with error conditions from the VDDC controller. If a hardware 299 ** error is present then the problem is reported on the console and the program 300 ** is halted. If a data error is present the a zero is returned. 301 ** If everything is OK then a 1 is returned. 302 */ 303 304 data_ok() 305 { 306 register int status = dcb.operrsta; 307 308 if(status & HARD_ERROR){ 309 if(status & DCBS_NRDY) 310 printf("\nDrive is not ready!"); 311 else if(status & DCBS_IVA) 312 printf("\nInvalid disk address issued!"); 313 else if(status & DCBS_NEM) 314 printf("\nNon-existent memory error!"); 315 else if(status & DCBS_DPE) 316 printf("\nMain memory parity error!"); 317 else if(status & DCBS_OAB) 318 printf("\nCPU aborted operation!"); 319 else if(status & DCBS_WPT) 320 printf("\nDrive is write protected!"); 321 else if(status & DCBS_SKI) 322 printf("\nDisk seek error!"); 323 else if(status & DCBS_CHE) 324 printf("\nController hardware error!"); 325 else 326 printf("\nNot on cylinder error!"); 327 printf(" Status = 0x%lx", status); 328 if(C_INFO->type == VDTYPE_SMDE) 329 printf(" Error code = 0x%x", dcb.err_code & 0xff); 330 printf("\n"); 331 printf("cylinder = %d, track = %d,", dcb.err_cyl, dcb.err_trk); 332 printf(" sector = %d, op = 0x%x\n", dcb.err_sec, dcb.opcode); 333 reset_controller(); 334 dcb.operrsta &= HEADER_ERROR; 335 } 336 return (int)(!(status & (DATA_ERROR | HEADER_ERROR))); 337 } 338 339 340 /* 341 ** 342 */ 343 344 reset_controller() 345 { 346 printf("Resetting controller. Please wait...\n"); 347 spin_up_drive(); 348 printf("Controller was reset successfully.\n"); 349 } 350 351 /* 352 ** 353 */ 354 355 static int indent_count; 356 357 358 /* 359 ** 360 */ 361 362 indent() 363 { 364 indent_count += 2; 365 } 366 367 368 /* 369 ** 370 */ 371 372 exdent(count) 373 int count; 374 { 375 if(count == -1) 376 indent_count = 0; 377 else 378 indent_count -= count * 2; 379 if(indent_count < 0) 380 indent_count = 0; 381 } 382 383 384 /* 385 ** 386 */ 387 /*VARARGS1*/ 388 print(par0, par1, par2, par3, par4, par5, par6) 389 char *par0, *par1, *par2, *par3, *par4, *par5, *par6; 390 { 391 register int count = indent_count; 392 393 while(count--) 394 printf(" "); 395 printf(par0, par1, par2, par3, par4, par5, par6); 396 DELAY((strlen(par0) + 20) * 9000); 397 } 398