📄 ftape-io.c
字号:
TRACE(2, "warning: error status set!"); result = 1; } TRACE_EXIT; return result;}int ftape_report_error(int *error, int *command, int report){ TRACE_FUN(8, "ftape_report_error"); int code; int result; result = ftape_report_operation(&code, QIC_REPORT_ERROR_CODE, 16); if (result < 0) { result = -EIO; } else { *error = code & 0xff; *command = (code >> 8) & 0xff; if (report) { if (*error != 0) { TRACEi(3, "errorcode:", *error); } else { TRACE(3, "No error"); } } if (report && *error != 0 && tracing > 3) { if (*error >= 0 && *error < NR_ITEMS(ftape_errors)) { TRACEx1(-1, "%sFatal ERROR:", (ftape_errors[*error].fatal ? "" : "Non-")); TRACEx1(-1, "%s ...", ftape_errors[*error].message); } else { TRACE(-1, "Unknown ERROR !"); } if (*command >= 0 && *command < NR_ITEMS(qic117_cmds) && qic117_cmds[*command].name != NULL) { TRACEx1(-1, "... caused by command \'%s\'", qic117_cmds[*command].name); } else { TRACEi(-1, "... caused by unknown command", *command); } } } TRACE_EXIT; return result;}int ftape_in_error_state(int status){ TRACE_FUN(8, "ftape_in_error_state"); int result = 0; if ((status & QIC_STATUS_READY) && (status & QIC_STATUS_ERROR)) { TRACE(2, "warning: error status set!"); result = 1; } TRACE_EXIT; return result;}static int ftape_report_configuration(qic_model * model, int *rate, int *qic_std, int *tape_len){ int result; int config; int status; TRACE_FUN(8, "ftape_report_configuration"); result = ftape_report_operation(&config, QIC_REPORT_DRIVE_CONFIGURATION, 8); if (result < 0) { *model = prehistoric; *rate = QIC_CONFIG_RATE_500; *qic_std = QIC_TAPE_QIC40; *tape_len = 205; result = 0; } else { *rate = (config & QIC_CONFIG_RATE_MASK) >> QIC_CONFIG_RATE_SHIFT; result = ftape_report_operation(&status, QIC_REPORT_TAPE_STATUS, 8); if (result < 0) { /* pre- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is valid. */ *qic_std = (config & QIC_CONFIG_80) ? QIC_TAPE_QIC80 : QIC_TAPE_QIC40; *tape_len = (config & QIC_CONFIG_LONG) ? 307 : 205; *model = pre_qic117c; result = 0; } else { *model = post_qic117b; TRACEx1(8, "report tape status result = %02x", status); /* post- QIC117 rev C spec. drive, QIC_CONFIG_80 bit is invalid. */ switch (status & QIC_TAPE_STD_MASK) { case QIC_TAPE_QIC40: case QIC_TAPE_QIC80: case QIC_TAPE_QIC3020: case QIC_TAPE_QIC3010: *qic_std = status & QIC_TAPE_STD_MASK; break; default: *qic_std = -1; break; } switch (status & QIC_TAPE_LEN_MASK) { case QIC_TAPE_205FT: /* Unfortunately the new QIC-117 rev G standard shows * no way to discriminate between 205 and 425 ft tapes. * The obvious way seems not to be used: the QIC_CONFIG_LONG * bit isn't used for this (on all drives ?). */ if (config & QIC_CONFIG_LONG) { *tape_len = 425; /* will this ever execute ??? */ } else { *tape_len = 0; /* length unknown: 205 or 425 ft. */ } break; case QIC_TAPE_307FT: *tape_len = 307; break; case QIC_TAPE_400FT: /* * Trouble! Iomega Ditto 800 and Conner TST800R drives reports * 400ft for 750ft tapes. Yuck, yuck, yuck. Since the value * is only used to compute a timeout value, the largest of the * two is used. */ *tape_len = 750; /* either 400 or 750 ft. */ break; case QIC_TAPE_1100FT: *tape_len = 1100; break; case QIC_TAPE_FLEX: *tape_len = 0; break; default: *tape_len = -1; break; } if (*qic_std == -1 || *tape_len == -1) { TRACE(2, "post qic-117b spec drive with unknown tape"); result = -EIO; } else { result = 0; } } } TRACE_EXIT; return (result < 0) ? -EIO : 0;}int ftape_report_rom_version(int *version){ int result; result = ftape_report_operation(version, QIC_REPORT_ROM_VERSION, 8); return (result < 0) ? -EIO : 0;}int ftape_report_signature(int *signature){ int result; result = ftape_command(28); result = ftape_report_operation(signature, 9, 8); result = ftape_command(30); return (result < 0) ? -EIO : 0;}void ftape_report_vendor_id(unsigned int *id){ TRACE_FUN(8, "ftape_report_vendor_id"); int result; /* * We'll try to get a vendor id from the drive. * First according to the QIC-117 spec, a 16-bit id is requested. * If that fails we'll try an 8-bit version, otherwise we'll try * an undocumented query. */ result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 16); if (result < 0) { result = ftape_report_operation((int *) id, QIC_REPORT_VENDOR_ID, 8); if (result < 0) { /* The following is an undocumented call found in the CMS code. */ result = ftape_report_operation((int *) id, 24, 8); if (result < 0) { *id = UNKNOWN_VENDOR; } else { TRACEx1(4, "got old 8 bit id: %04x", *id); *id |= 0x20000; } } else { TRACEx1(4, "got 8 bit id: %04x", *id); *id |= 0x10000; } } else { TRACEx1(4, "got 16 bit id: %04x", *id); } if (*id == 0x0047) { int version; int sign; result = ftape_report_rom_version(&version); if (result < 0) { TRACE(-1, "report rom version failed"); TRACE_EXIT; return; } TRACEx1(4, "CMS rom version: %d", version); ftape_command(QIC_ENTER_DIAGNOSTIC_1); ftape_command(QIC_ENTER_DIAGNOSTIC_1); result = ftape_report_operation(&sign, 9, 8); if (result < 0) { int error, command; ftape_report_error(&error, &command, 1); ftape_command(QIC_ENTER_PRIMARY_MODE); TRACE_EXIT; return; /* faalt hier ! */ } else { TRACEx1(4, "CMS signature: %02x", sign); } if (sign == 0xa5) { result = ftape_report_operation(&sign, 37, 8); if (result < 0) { if (version >= 63) { *id = 0x8880; TRACE(4, "This is an Iomega drive !"); } else { *id = 0x0047; TRACE(4, "This is a real CMS drive !"); } } else { *id = 0x0047; TRACEx1(4, "CMS status: %d", sign); } } else { *id = UNKNOWN_VENDOR; } ftape_command(QIC_ENTER_PRIMARY_MODE); } TRACE_EXIT;}void ftape_set_rate_test(int *supported){ TRACE_FUN(8, "ftape_set_rate_test"); int error; int command; int i; int result; int status; /* Check if the drive does support the select rate command by testing * all different settings. * If any one is accepted we assume the command is supported, else not. */ *supported = 0; for (i = 0; i < NR_ITEMS(rates); ++i) { result = ftape_command(QIC_SELECT_RATE); if (result >= 0) { result = ftape_parameter_wait(rates[i].drive_code, 1 * SECOND, &status); if (result >= 0) { if (status & QIC_STATUS_ERROR) { result = ftape_report_error(&error, &command, 0); } else { *supported = 1; /* did accept a request */ } } } } TRACEx1(4, "Select Rate command is%s supported", *supported ? "" : " not"); TRACE_EXIT;}int ftape_set_data_rate(int new_rate){ TRACE_FUN(8, "ftape_set_data_rate"); int status; int result; int data_rate; qic_model model; int supported; static int first_time = 1; if (first_time) { ftape_set_rate_test(&supported); first_time = 0; } if (rates[new_rate].fdc_code == -1) { TRACEx1(4, "%sb/s data rate not supported by the fdc", rates[new_rate].text); result = -EINVAL; } else { int error = 0; int command; result = ftape_command(QIC_SELECT_RATE); if (result >= 0) { result = ftape_parameter_wait(rates[new_rate].drive_code, 1 * SECOND, &status); result = ftape_report_raw_drive_status(&status); if (result >= 0 && (status & QIC_STATUS_ERROR)) { result = ftape_report_error(&error, &command, 0); if (result >= 0 && supported && error == 31 && command == QIC_SELECT_RATE) { result = -EINVAL; } } } if (result >= 0) { result = ftape_report_configuration(&model, &data_rate, &qic_std, &tape_len); if (result >= 0 && data_rate != rates[new_rate].drive_code) { result = -EINVAL; } } if (result < 0) { TRACEx1(4, "could not set %sb/s data rate", rates[new_rate].text); } else { TRACEx2(2, "%s drive @ %sb/s", (model == prehistoric) ? "prehistoric" : ((model == pre_qic117c) ? "pre QIC-117C" : ((model == post_qic117b) ? "post QIC-117B" : "post QIC-117D")), rates[new_rate].text); if (tape_len == 0) { TRACEx1(2, "unknown length QIC-%s tape", (qic_std == QIC_TAPE_QIC40) ? "40" : ((qic_std == QIC_TAPE_QIC80) ? "80" : ((qic_std == QIC_TAPE_QIC3010) ? "3010" : "3020"))); } else { TRACEx2(2, "%d ft. QIC-%s tape", tape_len, (qic_std == QIC_TAPE_QIC40) ? "40" : ((qic_std == QIC_TAPE_QIC80) ? "80" : ((qic_std == QIC_TAPE_QIC3010) ? "3010" : "3020"))); } /* * Set data rate and write precompensation as specified: * * | QIC-40/80 | QIC-3010/3020 * rate | precomp | precomp * ----------+-------------+-------------- * 250 Kbps. | 250 ns. | 0 ns. * 500 Kbps. | 125 ns. | 0 ns. * 1 Mbps. | 42 ns. | 0 ns. * 2 Mbps | N/A | 0 ns. */ if (qic_std == QIC_TAPE_QIC40 || qic_std == QIC_TAPE_QIC80) { fdc_set_write_precomp(rates[new_rate].precomp); } else { fdc_set_write_precomp(0); } fdc_set_data_rate(rates[new_rate].fdc_code); ftape_data_rate = new_rate; /* store rate set */ } } if (result < 0 && result != -EINVAL) { result = -EIO; } TRACE_EXIT; return result;}/* Seek the head to the specified track. */int ftape_seek_head_to_track(int track){ TRACE_FUN(8, "ftape_seek_head_to_track"); int status; int result; location.track = -1; /* remains set in case of error */ if (track < 0 || track >= tracks_per_tape) { TRACE(-1, "track out of bounds"); result = -EINVAL; } else { TRACEx1(5, "seeking track %d", track); result = ftape_command(QIC_SEEK_HEAD_TO_TRACK); if (result < 0) { TRACE(1, "ftape_command failed"); } else { result = ftape_parameter_wait(track, timeout.head_seek, &status); if (result < 0) { TRACE(1, "ftape_parameter_wait failed"); } else { location.track = track; might_be_off_track = 0; } } } TRACE_EXIT; return result;}int ftape_wakeup_drive(wake_up_types method){ TRACE_FUN(8, "ftape_wakeup_drive"); int result; int status; int motor_on = 0; switch (method) { case wake_up_colorado: result = ftape_command(QIC_PHANTOM_SELECT); if (result == 0) { result = ftape_parameter( /* unit */ 0); } break; case wake_up_mountain: result = ftape_command(QIC_SOFT_SELECT); if (result == 0) { ftape_sleep(MILLISECOND); /* NEEDED */ result = ftape_parameter(18); } break; case wake_up_insight: ftape_sleep(100 * MILLISECOND); motor_on = 1; fdc_motor(motor_on); /* enable is done by motor-on */ case no_wake_up: result = 0; break; default: result = -ENODEV; /* unknown wakeup method */ } /* If wakeup succeeded we shouldn't get an error here.. */ if (result == 0) { result = ftape_report_raw_drive_status(&status); if (result < 0 && motor_on) { fdc_motor(0); /* motor off if failed */ } } TRACE_EXIT; return result;}int ftape_put_drive_to_sleep(vendor_struct drive_type){ TRACE_FUN(8, "ftape_put_drive_to_sleep"); int result; switch (drive_type.wake_up) { case wake_up_colorado: result = ftape_command(QIC_PHANTOM_DESELECT); break; case wake_up_mountain: result = ftape_command(QIC_SOFT_DESELECT); break; case wake_up_insight: fdc_motor(0); /* enable is done by motor-on */ case no_wake_up: /* no wakeup / no sleep ! */ result = 0; break; default: result = -ENODEV; /* unknown wakeup method */ } TRACE_EXIT; return result;}int ftape_reset_drive(void){ TRACE_FUN(8, "ftape_reset_drive"); int result = 0; int status; int err_code; int err_command; int i; /* We want to re-establish contact with our drive. * Fire a number of reset commands (single step pulses) * and pray for success. */ for (i = 0; i < 2; ++i) { TRACE(5, "Resetting fdc"); fdc_reset(); ftape_sleep(10 * MILLISECOND); TRACE(5, "Reset command to drive"); result = ftape_command(QIC_RESET); if (result == 0) { ftape_sleep(1 * SECOND); /* drive not accessible during 1 second */ TRACE(5, "Re-selecting drive"); /* Strange, the QIC-117 specs don't mention this but the * drive gets deselected after a soft reset ! * So we need to enable it again. */ result = ftape_wakeup_drive(drive_type.wake_up); if (result < 0) { TRACE(1, "Wakeup failed !"); } TRACE(5, "Waiting until drive gets ready"); result = ftape_ready_wait(timeout.reset, &status); if (result == 0 && status & QIC_STATUS_ERROR) { result = ftape_report_error(&err_code, &err_command, 1); if (result == 0 && err_code == 27) { /* Okay, drive saw reset command and responded as it should */ break; } else { result = -EIO; } } else { result = -EIO; } } if (current->signal & _DONT_BLOCK) { TRACE(1, "aborted by non-blockable signal"); result = -EINTR; break; /* exit on signal */ } } if (result != 0) { TRACE(1, "General failure to reset tape drive"); } else { /* Restore correct settings */ ftape_set_data_rate(ftape_data_rate); /* keep original rate */ } TRACE_EXIT; return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -