Beispiel #1
0
/*
 * -- tapealert_mts - tapealert magnetic tape
 * If an error was produced on the general magnetic tape interface,
 * then request the log sense tapealert page 0x2e for processing.
 */
int			/* 0 successful */
tapealert_mts(
	char *fn,		/* source filename */
	int ln,			/* source file line number */
	int fd,			/* device file descriptor */
	dev_ent_t *un,		/* device */
	short mt_erreg)		/* mtio error register */
{
	if (un == NULL) {
		return (1);
	}

	/* inspect mtio for unrecovered check condition */
	if (UNRECOVERED_ERROR(mt_erreg)) {
		return (tapealert(fn, ln, fd, un, NULL, 0));
	}
	return (0);
}
Beispiel #2
0
/*
 * -- tapealert_skey - tapealert sense key
 * If a scsi command produced an unrecovered check condition, then
 * request the log sense tapealert page 0x2e for processing.
 */
int			/* 0 successful */
tapealert_skey(
	char *fn,		/* source filename */
	int ln,			/* source file line number */
	int fd,			/* device file descriptor */
	dev_ent_t *un)		/* device */
{
	sam_extended_sense_t	*sense;

	if (un == NULL) {
		return (1);
	}

	/* inspect sense data for unrecovered check condition */
	sense = (sam_extended_sense_t *)SHM_REF_ADDR(un->sense);
	if (UNRECOVERED_ERROR(sense->es_key)) {
		return (tapealert(fn, ln, fd, un, NULL, 0));
	}
	return (0);
}
Beispiel #3
0
// TODO, only handles drives where the interleave pattern is the same on all tracks
// TODO, this won't work when heads >= 8 for WD1003 which truncates head
// number in header to 3 bits.
static void analyze_sectors(DRIVE_PARAMS *drive_params, int cyl, void *deltas,
      int max_deltas) {
   int msg_mask_hold;
   // We return a pointer to this so it must be static (may be better to malloc)
   static uint8_t interleave[MAX_SECTORS];
   int unknown_interleave;
   int head_mismatch = 0;
   SECTOR_STATUS sector_status_list[MAX_SECTORS];
   int head;
   int found_header;
   int unrecovered_error;
   int max_sector, min_sector, last_good_head;
   int i;
   SECTOR_DECODE_STATUS status;

   // TODD, this should also detect the WD controllers that support 16 heads but only
    // put 0-7 in the header.
    max_sector = 0;
    min_sector = MAX_SECTORS;
    last_good_head = -1;
    unrecovered_error = 0;
    unknown_interleave = 0;
    memset(interleave, 255, sizeof(interleave));
    for (head = 0; head < MAX_HEAD && !head_mismatch; head++) {
       int found_bad_header;
       int err_count = 0;

       msg_mask_hold = msg_set_err_mask(decode_errors);
       // Try to get a good read. sector_status_list will be the best from
       // all the reads.
       do {
         drive_read_track(drive_params, cyl, head, deltas, max_deltas);

          mfm_init_sector_status_list(sector_status_list, drive_params->num_sectors);
          status = mfm_decode_track(drive_params, cyl, head, deltas, NULL, sector_status_list);
          if (UNRECOVERED_ERROR(status) && head == 8 && 
                drive_params->controller == CONTROLLER_WD_1006) {
             int good_header = 0;
             for (i = 0; i < drive_params->num_sectors; i++) {
                if ((sector_status_list[i].status & SECT_HEADER_FOUND) &&
                    !(sector_status_list[i].status & SECT_BAD_HEADER)) {
                   good_header = 1;
                }
             }
             // Mightyframe encodes head 8-15 differently. If we don't find
             // any good headers on head 8 see if its a Mightyframe.
             if (!good_header && head == 8) {
                drive_params->controller = CONTROLLER_MIGHTYFRAME;
                status = mfm_decode_track(drive_params, cyl, head, deltas, 
                    NULL, sector_status_list);
                for (i = 0; i < drive_params->num_sectors; i++) {
                   if ((sector_status_list[i].status & SECT_HEADER_FOUND) &&
                       !(sector_status_list[i].status & SECT_BAD_HEADER)) {
                      good_header = 1;
                   }
                }
                if (good_header) {
                   msg(MSG_FORMAT,"Changed controller type to %s\n",
                     mfm_controller_info[drive_params->controller].name);
                } else {
                   drive_params->controller = CONTROLLER_WD_1006;
                   status = mfm_decode_track(drive_params, cyl, head, deltas, 
                       NULL, sector_status_list);
                }
             }
          }
       } while (UNRECOVERED_ERROR(status) && ++err_count < 8);
       msg_set_err_mask(msg_mask_hold);
       if (UNRECOVERED_ERROR(status)) {
          unrecovered_error = 1;
       }
       found_bad_header = 0;
       found_header = 0;
       for (i = 0; i < drive_params->num_sectors; i++) {
          // If we missed a header after finding one, stop looking at
          // interleave since it is likely to be wrong. With
          // read errors we still may get confused.
          if ((sector_status_list[i].status & SECT_BAD_HEADER) && found_header) {
             found_bad_header = 1;
          }
          if (sector_status_list[i].status & SECT_HEADER_FOUND) {
             found_header = 1;
             if (!found_bad_header) {
                if (interleave[sector_status_list[i].logical_sector] != 255 &&
                      interleave[sector_status_list[i].logical_sector] !=
                            sector_status_list[i].sector && !unknown_interleave) {
                   msg(MSG_ERR, "Interleave mismatch previous entry %d, %d was %d now %d\n",
                         i, sector_status_list[i].logical_sector,
                         interleave[sector_status_list[i].logical_sector],
                         sector_status_list[i].sector);
                   unknown_interleave = 1;
                }
                interleave[sector_status_list[i].logical_sector] = sector_status_list[i].sector;
             }
             max_sector = MAX(max_sector, sector_status_list[i].sector);
             min_sector = MIN(min_sector, sector_status_list[i].sector);
             if (sector_status_list[i].head == head) {
                last_good_head = head;
             } else {
                if (!head_mismatch) {
                   msg(MSG_INFO, "Selected head %d found %d, last good head found %d\n",
                         head, sector_status_list[i].head, last_good_head);
                   head_mismatch = 1;
                }
             }
          }
       }
    }
    // If we had a read error but got some good error warn. If nothing readable
    // assume we were trying to read an invalid head
    if (unrecovered_error && found_header) {
       msg(MSG_ERR, "Read errors trying to determine sector numbering, results may be in error\n");
    }
    if (last_good_head == -1) {
       msg(MSG_FATAL, "Unable to determine number of heads\n");
       exit(1);
    }
    // We store number of heads, not maximum head number (starting at 0)
    drive_params->num_head = last_good_head+1;
    drive_params->num_sectors = max_sector - min_sector + 1;
    drive_params->first_sector_number = min_sector;
    msg(MSG_INFO, "Number of heads %d number of sectors %d first sector %d\n",
          drive_params->num_head, drive_params->num_sectors,
          drive_params->first_sector_number);

    if (unknown_interleave) {
       msg(MSG_ERR, "Unable to determine interleave. Interleave value is not required\n");
       drive_params->sector_numbers = NULL;
    } else {
       msg(MSG_INFO, "Interleave (not checked):");
       for (i = 0; i < drive_params->num_sectors; i++) {
          msg(MSG_INFO, " %d",interleave[i]);
       }
       msg(MSG_INFO, "\n");
       // Too many drives have cylinders with different interleave (spare,
       // for testing) that cause confusing errors so checking is disabled
       // unless users specified directly
       //drive_params->sector_numbers = interleave;
       drive_params->sector_numbers = NULL;
    }
}
Beispiel #4
0
// Try to find the sector size and CRC parameters for the data portion of
// sectors.
// The data to analyze has already been read before routine called.
//
// drive_params: Drive parameters determined so far and return what we have determined
// deltas: MFM delta time transition data to analyze
// return: 0 ok, 1 multiple matches found, 2 unable to find format
static int analyze_data(DRIVE_PARAMS *drive_params, int cyl, int head, void *deltas, int max_deltas)
{
   // Loop variables
   int poly, init, size_ndx;
   int i;
   // The best match CRC and sector size info so far
   CRC_INFO data_crc_info;
   // And read status
   SECTOR_DECODE_STATUS status;
   int sector_size = 0;
   // Numbers of good sectors found
   int good_data_count, previous_good_data_count = 0;
   // Variable to restore global error print mask
   int msg_mask_hold;
   // The status of each sector decoded.
   SECTOR_STATUS sector_status_list[MAX_SECTORS];
   // Return code
   int rc = 0;

   drive_read_track(drive_params, cyl, head, deltas, max_deltas);

   data_crc_info.poly = 0;
   // Try an exhaustive search of all the formats we know about. If we get too
   // many we may have to try something smarter.
   for (poly = mfm_controller_info[drive_params->controller].data_start_poly; 
          poly < mfm_controller_info[drive_params->controller].data_end_poly; poly++) {
      drive_params->data_crc.poly = mfm_all_poly[poly].poly;
      drive_params->data_crc.length = mfm_all_poly[poly].length;
      // This sometimes gets false corrections when using wrong polynomial
      // We put it back when we save the best value.
      drive_params->data_crc.ecc_max_span = 0;
      for (init = mfm_controller_info[drive_params->controller].start_init; 
            init < mfm_controller_info[drive_params->controller].end_init; init++) {
         // If not correct size don't try this initial value
         if (!(mfm_all_init[init].length == -1 || mfm_all_init[init].length ==
              drive_params->data_crc.length)) {
            continue;
         }
         drive_params->data_crc.init_value = trim_value(mfm_all_init[init].value,
               drive_params->data_crc.length);
         for (size_ndx = 0; mfm_all_sector_size[size_ndx] != -1; size_ndx++) {
            drive_params->sector_size = mfm_all_sector_size[size_ndx];
            mfm_init_sector_status_list(sector_status_list, drive_params->num_sectors);
            msg_mask_hold = msg_set_err_mask(decode_errors);
            // Decode track
            status = mfm_decode_track(drive_params, cyl, head, deltas, NULL, sector_status_list);
            msg_set_err_mask(msg_mask_hold);
            if (status & SECT_ZERO_DATA_CRC) {
               msg(MSG_DEBUG, "Found zero CRC data size %d:\n", drive_params->sector_size);
               print_crc_info(&drive_params->data_crc, MSG_DEBUG);

            }
            // Now find out how many good sectors we got with these parameters
            good_data_count = 0;
            for (i = 0; i < drive_params->num_sectors; i++) {
               if (!UNRECOVERED_ERROR(sector_status_list[i].status)) {
                  good_data_count++;
               }
            }
            // If we found a good sector
            if (good_data_count > 0) {
               // If we have a previous match print both
               if (data_crc_info.poly != 0) {
                  msg(MSG_ERR_SERIOUS,
                     "Found multiple matching data CRC parameters. Largest matches will be used:\n");
                  msg(MSG_ERR_SERIOUS, "Matches %d sector size %d ", good_data_count,
                        drive_params->sector_size);
                  print_crc_info(&drive_params->data_crc, MSG_ERR_SERIOUS);
                  msg(MSG_ERR_SERIOUS, "Matches %d sector size %d ", previous_good_data_count,
                        sector_size);
                  print_crc_info(&data_crc_info, MSG_ERR_SERIOUS);
                  rc = 1;
               }
               // And keep the best
               if (good_data_count > previous_good_data_count) {
                  data_crc_info = drive_params->data_crc;
                  data_crc_info.ecc_max_span = mfm_all_poly[poly].ecc_span;
                  sector_size = drive_params->sector_size;
                  previous_good_data_count = good_data_count;
               }
            }
         }
      }
   }
   // Print what we found and put it in drive_params
   if (data_crc_info.poly != 0) {
      msg(MSG_INFO, "Sector length %d, Data CRC Information:\n", sector_size);
      print_crc_info(&data_crc_info, MSG_INFO);
   } else {
      // This is fatal since if we can't continue to next analysis
      msg(MSG_FATAL, "Unable to determine DATA CRC type\n");
      rc = 2;
   }
   drive_params->sector_size = sector_size;
   drive_params->data_crc = data_crc_info;
   return rc;
}