// Find the number of cylinders the disk has. We step down the disk until we // find unreadable tracks, the cylinder number in header doesn't match, or // seek times out. Various disks have different behavior. The tracks past the end // leading to the park zone are normally not formated. Many drives won't let you // seek past the last cylinder. They either return to track zero or perform a // recalibrate which may take enough time for the seek to timeout. Really old // disk will just hit the end stop so can get the same cylinder. Hitting end stop // probably isn't great. // // drive_params: Drive parameters determined so far and return what we have determined // start_cyl: cylinder head is on at entry // head: head currently selected // deltas: MFM delta time transition data to analyze (filled after read) // // TODO, this won't deal well with spared cylinders when they have nonsequential // values static void analyze_disk_size(DRIVE_PARAMS *drive_params, int start_cyl, int head, void *deltas, int max_deltas) { int msg_mask_hold; int max_cyl; int not_next_cyl, not_next_cyl_count; int any_header_found; int no_header_count; SECTOR_STATUS sector_status_list[MAX_SECTORS]; int cyl; int i; int last_printed_cyl; max_cyl = 0; no_header_count = 0; not_next_cyl_count = 0; for (cyl = start_cyl + 1; cyl < MAX_CYL; cyl++) { if (cyl % 5 == 0) msg(MSG_PROGRESS, "At cyl %d\r", cyl); if (drive_step(drive_params->step_speed, 1, DRIVE_STEP_UPDATE_CYL, DRIVE_STEP_RET_ERR) != 0) { msg(MSG_INFO, "Max cylinder set from drive timeout on seek\n"); break; } drive_read_track(drive_params, cyl, head, deltas, max_deltas); mfm_init_sector_status_list(sector_status_list, drive_params->num_sectors); msg_mask_hold = msg_set_err_mask(decode_errors); mfm_decode_track(drive_params, cyl, head, deltas, NULL, sector_status_list); msg_set_err_mask(msg_mask_hold); any_header_found = 0; not_next_cyl = 0; last_printed_cyl = -1; for (i = 0; i < drive_params->num_sectors; i++) { if (sector_status_list[i].status & SECT_HEADER_FOUND) { any_header_found = 1; max_cyl = MAX(max_cyl, sector_status_list[i].cyl); if (cyl != sector_status_list[i].cyl && last_printed_cyl != cyl) { msg(MSG_INFO, "Found cylinder %d expected %d\n",sector_status_list[i].cyl, cyl); last_printed_cyl = cyl; not_next_cyl = 1; } } } if (!any_header_found) { if (++no_header_count >= 2) { msg(MSG_INFO, "Stopping end of disk search due to two unreadable tracks in a row\n"); break; } else { msg(MSG_INFO, "No sectors readable from cylinder %d\n",cyl); } } else { no_header_count = 0; } if (not_next_cyl) { if (++not_next_cyl_count >= 2) { msg(MSG_INFO, "Stopping end of disk search due to mismatching cylinder count\n"); break; } } else { not_next_cyl_count = 0; } } drive_params->num_cyl = max_cyl + 1; msg(MSG_INFO, "Number of cylinders %d, %.1f MB\n", drive_params->num_cyl, (double) drive_params->num_cyl * drive_params->num_head * drive_params->num_sectors * drive_params->sector_size / (1000.0*1000)); // We don't know where head is so return to 0 drive_seek_track0(); }
static void process_cmd( wd1793_t *device ) { unsigned char cmd = device->command; if ( (cmd & 0x80) == 0 ) { // type I command device->status = STAT_BUSY; device->out_status &= ~(WD1793_DRQ | WD1793_INTRQ); if ( FLAG_H(cmd) ) device->out_status |= WD1793_HLD; else device->out_status &= ~WD1793_HLD; if ( (cmd & 0xE0) == 0 ) { // seek and restore commands if ( (cmd & 0x10) == 0 ) { // restore command device->track = 0xFF; device->data = 0; } device->dsr = device->data; while ( device->dsr != device->track ) { if ( device->dsr > device->track ) { device->out_status |= WD1793_DIR; device->track ++; } else { device->out_status &= ~WD1793_DIR; device->track --; } drive_step( device ); } } else { // step commands if ( (cmd & 0x60) == 4 ) // step in device->out_status |= WD1793_DIR; else if ( (cmd & 0x60) == 6 ) // step out device->out_status &= ~WD1793_DIR; if ( FLAG_U(cmd) ) { if ( device->out_status & WD1793_DIR ) device->track ++; else device->track --; } drive_step( device ); } /*if ( !(device->out_status & WD1793_DIR) && (device->disk.track == 0) ) { device->track = 0; device->count = 1; // no delay } else { drive_step( device ); device->count = pos_delays[FLAG_R(cmd)]; }*/ device->state = WD1793_TYPE1; // HACK device->status &= ~(STAT_BUSY | STAT_TRACK_0); if ( device->disk.track == 0 ) { device->status |= STAT_TRACK_0; device->track = 0; } device->out_status |= WD1793_INTRQ; } else if ( (cmd & 0x40) == 0 ) { // type II command device->status |= STAT_BUSY; } else if ( (cmd & 0x30) == 0x01 ) { // type IV command device->status &= ~STAT_BUSY; } else { // type III command device->status |= STAT_BUSY; } }