2 Bacula® - The Network Backup Solution
4 Copyright (C) 2006-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * mtops.c - Emulate the Linux st (scsi tape) driver on file.
38 #include "bacula.h" /* pull in global headers */
39 #include "stored.h" /* pull in Storage Deamon headers */
44 // SCSI bus status codes.
47 #define SCSISTAT_GOOD 0x00
48 #define SCSISTAT_CHECK_CONDITION 0x02
49 #define SCSISTAT_CONDITION_MET 0x04
50 #define SCSISTAT_BUSY 0x08
51 #define SCSISTAT_INTERMEDIATE 0x10
52 #define SCSISTAT_INTERMEDIATE_COND_MET 0x14
53 #define SCSISTAT_RESERVATION_CONFLICT 0x18
54 #define SCSISTAT_COMMAND_TERMINATED 0x22
55 #define SCSISTAT_QUEUE_FULL 0x28
57 static int tape_get(int fd, struct mtget *mt_get);
58 static int tape_op(int fd, struct mtop *mt_com);
59 static int tape_pos(int fd, struct mtpos *mt_pos);
62 fake_tape_open(const char *file, int flags, int mode)
65 fd = open(file, flags, mode);
70 fake_tape_read(int fd, void *buffer, unsigned int count)
77 ret = read(fd, buffer, count);
82 fake_tape_write(int fd, const void *buffer, unsigned int count)
89 ret = write(fd, buffer, count);
94 fake_tape_close(int fd)
101 fake_tape_ioctl(int fd, unsigned long int request, ...)
106 va_start(argp, request);
110 result = tape_op(fd, va_arg(argp, mtop *));
114 result = tape_get(fd, va_arg(argp, mtget *));
118 result = tape_pos(fd, va_arg(argp, mtpos *));
132 static int tape_op(int fd, struct mtop *mt_com)
136 switch (mt_com->mt_op)
153 for (index = 0; index < mt_com->mt_count; index++) {
154 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
155 if (result == NO_ERROR) {
156 pHandleInfo->ulFile++;
157 pHandleInfo->bEOF = true;
158 pHandleInfo->bEOT = false;
164 for (index = 0; index < mt_com->mt_count; index++) {
165 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
166 if (result == NO_ERROR) {
167 pHandleInfo->ulFile--;
168 pHandleInfo->bBlockValid = false;
169 pHandleInfo->bEOD = false;
170 pHandleInfo->bEOF = false;
171 pHandleInfo->bEOT = false;
177 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE);
178 if (result == NO_ERROR) {
179 pHandleInfo->bEOD = false;
180 pHandleInfo->bEOF = false;
181 pHandleInfo->bEOT = false;
182 } else if (result == ERROR_FILEMARK_DETECTED) {
183 pHandleInfo->bEOF = true;
188 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE);
189 if (result == NO_ERROR) {
190 pHandleInfo->bEOD = false;
191 pHandleInfo->bEOF = false;
192 pHandleInfo->bEOT = false;
193 } else if (result == ERROR_FILEMARK_DETECTED) {
194 pHandleInfo->ulFile--;
195 pHandleInfo->bBlockValid = false;
196 pHandleInfo->bEOD = false;
197 pHandleInfo->bEOF = false;
198 pHandleInfo->bEOT = false;
203 result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE);
204 if (result == NO_ERROR) {
205 pHandleInfo->bEOF = true;
206 pHandleInfo->bEOT = false;
207 pHandleInfo->ulFile += mt_com->mt_count;
208 pHandleInfo->bBlockValid = true;
209 pHandleInfo->ullFileStart = 0;
214 if (lseek(fd, (boffset_t)0, SEEK_SET) < 0) {
217 Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
218 print_name(), be.bstrerror());
226 result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
227 if (result == NO_ERROR) {
228 pHandleInfo->bEOD = false;
229 pHandleInfo->bEOF = false;
230 pHandleInfo->bEOT = false;
231 pHandleInfo->ulFile = 0;
232 pHandleInfo->ullFileStart = 0;
237 result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE);
238 if (result == NO_ERROR) {
239 pHandleInfo->bEOD = false;
240 pHandleInfo->bEOF = false;
241 pHandleInfo->bEOT = false;
242 pHandleInfo->ulFile = 0;
243 pHandleInfo->bBlockValid = true;
244 pHandleInfo->ullFileStart = 0;
249 for (index = 0; index < mt_com->mt_count; index++) {
250 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
251 if (result == NO_ERROR) {
252 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
253 pHandleInfo->bEOD = false;
254 pHandleInfo->bEOF = false;
255 pHandleInfo->bEOT = false;
261 for (index = 0; index < mt_com->mt_count; index++) {
262 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE);
263 if (result == NO_ERROR) {
264 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
265 pHandleInfo->bEOD = false;
266 pHandleInfo->bEOF = false;
267 pHandleInfo->bEOT = false;
274 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
275 if (result != NO_ERROR) {
276 pHandleInfo->bEOF = false;
278 if (result == ERROR_END_OF_MEDIA) {
279 pHandleInfo->bEOD = true;
280 pHandleInfo->bEOT = true;
283 if (result == ERROR_NO_DATA_DETECTED) {
284 pHandleInfo->bEOD = true;
285 pHandleInfo->bEOT = false;
290 pHandleInfo->bEOF = true;
291 pHandleInfo->ulFile++;
297 result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE);
298 if (result == NO_ERROR) {
299 pHandleInfo->bEOD = true;
300 pHandleInfo->bEOF = false;
301 pHandleInfo->bEOT = false;
302 pHandleInfo->ulFile = 0;
303 pHandleInfo->bBlockValid = true;
304 pHandleInfo->ullFileStart = 0;
310 TAPE_SET_MEDIA_PARAMETERS SetMediaParameters;
312 SetMediaParameters.BlockSize = mt_com->mt_count;
313 result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters);
319 TAPE_POSITION_INFO TapePositionInfo;
321 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE);
323 memset(&TapePositionInfo, 0, sizeof(TapePositionInfo));
324 DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
325 if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) {
326 pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
328 pHandleInfo->ulFile = ~0U;
339 result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
340 if (result == NO_ERROR) {
347 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE);
351 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE);
355 result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE);
359 result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE);
363 result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE);
367 result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE);
371 result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
376 TAPE_GET_DRIVE_PARAMETERS GetDriveParameters;
377 TAPE_SET_DRIVE_PARAMETERS SetDriveParameters;
380 size = sizeof(GetDriveParameters);
382 result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters);
384 if (result == NO_ERROR)
386 SetDriveParameters.ECC = GetDriveParameters.ECC;
387 SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count;
388 SetDriveParameters.DataPadding = GetDriveParameters.DataPadding;
389 SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks;
390 SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize;
392 result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters);
398 result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE);
402 if (mt_com->mt_count == 0)
404 result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0);
408 result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count);
413 if ((result == NO_ERROR && pHandleInfo->bEOF) ||
414 (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) {
416 TAPE_POSITION_INFO TapePositionInfo;
418 if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) {
419 pHandleInfo->bBlockValid = true;
420 pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber;
426 case (DWORD)-1: /* Error has already been translated into errno */
430 case ERROR_FILEMARK_DETECTED:
434 case ERROR_END_OF_MEDIA:
435 pHandleInfo->bEOT = true;
439 case ERROR_NO_DATA_DETECTED:
440 pHandleInfo->bEOD = true;
444 case ERROR_NO_MEDIA_IN_DRIVE:
445 pHandleInfo->bEOF = false;
446 pHandleInfo->bEOT = false;
447 pHandleInfo->bEOD = false;
451 case ERROR_INVALID_HANDLE:
452 case ERROR_ACCESS_DENIED:
453 case ERROR_LOCK_VIOLATION:
458 return result == NO_ERROR ? 0 : -1;
461 static int tape_get(int fd, struct mtget *mt_get)
463 TAPE_POSITION_INFO pos_info;
466 if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
467 TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
472 PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
474 if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) {
481 result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize);
483 if (result != NO_ERROR) {
484 TAPE_GET_DRIVE_PARAMETERS drive_params;
487 size = sizeof(drive_params);
489 result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params);
491 if (result == NO_ERROR) {
492 blocksize = drive_params.DefaultBlockSize;
496 mt_get->mt_type = MT_ISSCSI2;
499 mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
501 // Density / Block Size
502 mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
503 ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
505 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
507 if (pHandleInfo->bEOF) {
508 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
511 if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) {
512 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
515 if (pHandleInfo->bEOT) {
516 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
519 if (pHandleInfo->bEOD) {
520 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
523 TAPE_GET_MEDIA_PARAMETERS media_params;
524 DWORD size = sizeof(media_params);
526 result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params);
528 if (result == NO_ERROR && media_params.WriteProtected) {
529 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
532 result = GetTapeStatus(pHandleInfo->OSHandle);
534 if (result != NO_ERROR) {
535 if (result == ERROR_NO_MEDIA_IN_DRIVE) {
536 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
539 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
542 // Recovered Error Count
543 mt_get->mt_erreg = 0;
546 mt_get->mt_fileno = (__daddr_t)pHandleInfo->ulFile;
549 mt_get->mt_blkno = (__daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1);