# as values. Each slot's hash has keys
# state - SLOT_FULL/SLOT_EMPTY/SLOT_UNKNOWN
# device_status - the status of the device
+# device_error - the error message of the device
# f_type - The f_type of the header
# label - volume label, if known
# barcode - volume barcode, if available
}
# eject-before-unload
- my $ebu = $self->get_boolean_property($self->{'config'},
+ my $ebu = $self->{'config'}->get_boolean_property(
"eject-before-unload", 0);
if (!defined $ebu) {
return Amanda::Changer->make_error("fatal", undef,
$self->{'eject_before_unload'} = $ebu;
# fast-search
- my $fast_search = $self->get_boolean_property($self->{'config'},
+ my $fast_search = $self->{'config'}->get_boolean_property(
"fast-search", 1);
if (!defined $fast_search) {
return Amanda::Changer->make_error("fatal", undef,
}
# status-interval, eject-delay, unload-delay
- for my $propname qw(status-interval eject-delay unload-delay) {
+ for my $propname (qw(status-interval eject-delay unload-delay)) {
next unless exists $config->{'properties'}->{$propname};
if (@{$config->{'properties'}->{$propname}->{'values'}} > 1) {
return Amanda::Changer->make_error("fatal", undef,
$self->{$key} = $time;
}
- my $ignore_barcodes = $self->get_boolean_property($self->{'config'},
+ my $ignore_barcodes = $self->{'config'}->get_boolean_property(
"ignore-barcodes", 0);
if (!defined $ignore_barcodes) {
return Amanda::Changer->make_error("fatal", undef,
if ($state->{'slots'}->{$slot}->{'state'} eq Amanda::Changer::SLOT_EMPTY) {
return $self->make_error("failed", $params{'res_cb'},
- reason => "notfound",
+ reason => "empty",
message => "slot $slot is empty");
}
}
# otherwise, we can jump all the way to the end of this process
- return $steps->{'check_device'}->();
+ return $steps->{'start_polling'}->();
}
# here is where we implement each of the drive-selection algorithms
} elsif ($device->status & $DEVICE_STATUS_VOLUME_UNLABELED) {
$label = undef;
} else {
- return $self->make_error("fatal", $params{'res_cb'},
- message => "while waiting for '$device_name' to become ready: "
- . $device->error_or_status());
+ $label = undef;
}
# success!
# update metadata with this new information
$state->{'slots'}->{$slot}->{'state'} = Amanda::Changer::SLOT_FULL;
$state->{'slots'}->{$slot}->{'device_status'} = $device->status;
- if (defined $device->{'header'}) {
- $state->{'slots'}->{$slot}->{'f_type'} = $device->{'header'}->{type};
+ $state->{'slots'}->{$slot}->{'device_error'} = $device->error;
+ if (defined $device->{'volume_header'}) {
+ $state->{'slots'}->{$slot}->{'f_type'} = $device->{'volume_header'}->{type};
} else {
$state->{'slots'}->{$slot}->{'f_type'} = undef;
}
# update metadata with this new information
$state->{'slots'}->{$slot}->{'state'} = Amanda::Changer::SLOT_FULL;
$state->{'slots'}->{$slot}->{'device_status'} = $device->status;
- if (defined $device->{'header'}) {
- $state->{'slots'}->{$slot}->{'f_type'} = $device->{'header'}->{type};
+ $state->{'slots'}->{$slot}->{'device_error'} = $device->error;
+ if (defined $device->{'volume_header'}) {
+ $state->{'slots'}->{$slot}->{'f_type'} = $device->{'volume_header'}->{type};
} else {
$state->{'slots'}->{$slot}->{'f_type'} = undef;
}
$state->{'drives'}->{$drive}->{'label'} = $label;
$state->{'drives'}->{$drive}->{'state'} = Amanda::Changer::SLOT_FULL;
$state->{'drives'}->{$drive}->{'barcode'} = $state->{'slots'}->{$slot}->{'barcode'};
- #$state->{'slots'}->{$slot}->{'device_status'} = 9;
+ $state->{'slots'}->{$slot}->{'device_status'} = $device->status;
if ($label and $state->{'slots'}->{$slot}->{'barcode'}) {
$state->{'bc2lb'}->{$state->{'slots'}->{$slot}->{'barcode'}} = $label;
}
$self->{'interface'}->inquiry(make_cb(inquiry_cb => sub {
my ($err, $info) = @_;
- return $params{'info_cb'}->($err) if $err;
+ return $self->make_error("fatal", $params{'info_cb'},
+ message => "$err") if $err;
my $vendor_string = sprintf "%s %s",
($info->{'vendor id'} or "<unknown>"),
my $device = Amanda::Device->new($device_name);
if ($device->status != $DEVICE_STATUS_SUCCESS) {
- return $self->make_error("failed", undef,
- reason => "device",
+ return Amanda::Changer->make_error("fatal", undef,
+ reason => "unknown",
message => "opening '$device_name': " . $device->error_or_status());
}
if (my $err = $self->{'config'}->configure_device($device)) {
- return $self->make_error("failed", undef,
- reason => "device",
+ return Amanda::Changer->make_error("fatal", undef,
+ reason => "unknown",
message => $err);
}
$state->{'drives'}->{$drive}->{'label'} = $label;
if (defined $slot) {
- delete $state->{'slots'}->{$slot}->{'unkknown_state'};
$state->{'slots'}->{$slot}->{'state'} = Amanda::Changer::SLOT_FULL;
$state->{'slots'}->{$slot}->{'device_status'} = "".$dev->status;
+ if ($dev->status != $DEVICE_STATUS_SUCCESS) {
+ $state->{'slots'}->{$slot}->{'device_error'} = $dev->error;
+ } else {
+ $state->{'slots'}->{$slot}->{'device_error'} = undef;
+ }
my $volume_header = $dev->volume_header;
if (defined $volume_header) {
$state->{'slots'}->{$slot}->{'f_type'} = "".$volume_header->{type};
while (my ($sl, $inf) = each %{$state->{'slots'}}) {
if ($inf->{'label'} and $inf->{'label'} eq $label) {
delete $inf->{'device_status'};
+ delete $inf->{'device_error'};
delete $inf->{'f_type'};
delete $inf->{'label'};
}
if (!defined $state->{'slots'}->{$slot}->{'barcode'}) {
$state->{'slots'}->{$slot}->{'label'} = undef;
$state->{'slots'}->{$slot}->{'device_status'} = undef;
+ $state->{'slots'}->{$slot}->{'device_error'} = undef;
$state->{'slots'}->{$slot}->{'f_type'} = undef;
if (defined $state->{'slots'}->{$slot}->{'loaded_in'}) {
my $drive = $state->{'slots'}->{$slot}->{'loaded_in'};
$i->{'slot'} = $slot_name;
$i->{'state'} = $slot->{'state'};
$i->{'device_status'} = $slot->{'device_status'};
+ $i->{'device_error'} = $slot->{'device_error'};
$i->{'f_type'} = $slot->{'f_type'};
$i->{'label'} = $slot->{'label'};
$i->{'barcode'} = $slot->{'barcode'}
message => "slot $from_slot is empty");
}
- if (defined $state->{'slots'}->{$from_slot}->{'loaded_in'}) {
- return $self->make_error("failed", $params{'finished_cb'},
- reason => "invalid",
- message => "slot $from_slot is currently loaded");
+ my $in_drive = $state->{'slots'}->{$from_slot}->{'loaded_in'};
+ if (defined $in_drive) {
+ my $info = $state->{'drives'}->{$in_drive};
+ if ($info->{'res_info'} and $self->_res_info_verify($info->{'res_info'})) {
+ return $self->make_error("failed", $params{'finished_cb'},
+ reason => "invalid",
+ message => "slot $from_slot is currently loaded and reserved");
+ }
}
if ($state->{'slots'}->{$to_slot}->{'state'} == Amanda::Changer::SLOT_FULL) {
return $params{'finished_cb'}->($err) if $err;
# update metadata
- $state->{'slots'}->{$to_slot} = { %{ $state->{'slots'}->{$from_slot} } };
- $state->{'slots'}->{$from_slot}->{'state'} =
- Amanda::Changer::SLOT_EMPTY;
- $state->{'slots'}->{$from_slot}->{'device_status'} = undef;
- $state->{'slots'}->{$from_slot}->{'f_type'} = undef;
- $state->{'slots'}->{$from_slot}->{'label'} = undef;
- $state->{'slots'}->{$from_slot}->{'barcode'} = undef;
+ if ($from_slot ne $to_slot) {
+ my $f = $state->{'slots'}->{$from_slot};
+ my $t = $state->{'slots'}->{$to_slot};
+
+ $t->{'device_status'} = $f->{'device_status'};
+ $f->{'device_status'} = undef;
+
+ $t->{'state'} = $f->{'state'};
+ $f->{'state'} = Amanda::Changer::SLOT_EMPTY;
+
+ $t->{'f_type'} = $f->{'f_type'};
+ $f->{'f_type'} = undef;
+
+ $t->{'label'} = $f->{'label'};
+ $f->{'label'} = undef;
+
+ $t->{'barcode'} = $f->{'barcode'};
+ $f->{'barcode'} = undef;
+ }
+
+ # properly represent the unload operation, if it was performed
+ if (defined $in_drive) {
+ $state->{'slots'}->{$from_slot}->{'loaded_in'} = undef;
+ $state->{'slots'}->{$to_slot}->{'loaded_in'} = undef;
+
+ $state->{'drives'}->{$in_drive}->{'state'} =
+ Amanda::Changer::SLOT_EMPTY;
+ $state->{'drives'}->{$in_drive}->{'label'} = undef;
+ $state->{'drives'}->{$in_drive}->{'barcode'} = undef;
+ $state->{'drives'}->{$in_drive}->{'orig_slot'} = undef;
+ }
$params{'finished_cb'}->();
});
- $self->{'interface'}->transfer($from_slot, $to_slot, $transfer_complete);
+
+ # if the source slot is loaded, then this is just a directed unload operation;
+ # otherwise, it's a transfer.
+ if (defined $in_drive) {
+ Amanda::Debug::debug("move(): unloading drive $in_drive to slot $to_slot");
+ $self->{'interface'}->unload($in_drive, $to_slot, $transfer_complete);
+ } else {
+ $self->{'interface'}->transfer($from_slot, $to_slot, $transfer_complete);
+ }
}
##
$new_slots->{$slot} = {
state => Amanda::Changer::SLOT_EMPTY,
device_status => undef,
+ device_error => undef,
f_type => undef,
label => undef,
barcode => undef,
$new_slots->{$slot} = {
state => Amanda::Changer::SLOT_FULL,
device_status => $state->{'slots'}->{$slot}->{device_status},
+ device_error => $state->{'slots'}->{$slot}->{device_error},
f_type => $state->{'slots'}->{$slot}->{f_type},
label => $label,
barcode => $info->{'barcode'},
$new_slots->{$slot} = {
state => Amanda::Changer::SLOT_FULL,
device_status => undef,
+ device_error => undef,
f_type => undef,
label => undef,
barcode => undef,
$state->{'slots'}->{$info->{'orig_slot'}} = {
state => $info->{'state'},
device_status => $old_state->{'device_status'},
+ device_error => $old_state->{'device_error'},
f_type => $old_state->{'f_type'},
label => $info->{'label'},
barcode => $info->{'barcode'},
synchronized($self->{'lock'}, $status_cb, sub {
my ($status_cb) = @_;
+ my ($counter) = 120;
+
+ my $sys_cb;
+ my $run_mtx = make_cb(run_mtx => sub {
+ my @nobarcode = ('nobarcode') if $self->{'ignore_barcodes'};
+ $self->_run_system_command($sys_cb,
+ $self->{'mtx'}, "-f", $self->{'device_name'}, @nobarcode,
+ 'status');
+ });
- my $sys_cb = make_cb(sys_cb => sub {
+ $sys_cb = make_cb(sys_cb => sub {
my ($exitstatus, $output) = @_;
if ($exitstatus != 0) {
my $err = $output;
# if it's a regular SCSI error, just show the sense key
my ($sensekey) = ($err =~ /mtx: Request Sense: Sense Key=(.*)\n/);
$err = "SCSI error; Sense Key=$sensekey" if $sensekey;
+ $counter--;
+ if ($sensekey eq "Not Ready" and $counter > 0) {
+ debug("$output");
+ return Amanda::MainLoop::call_after(1000, $run_mtx);
+ }
return $status_cb->("error from mtx: " . $err, {});
} else {
my %status;
}
});
- my @nobarcode = ('nobarcode') if $self->{'ignore_barcodes'};
- $self->_run_system_command($sys_cb,
- $self->{'mtx'}, "-f", $self->{'device_name'}, @nobarcode, 'status');
+ $run_mtx->();
});
}