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