DriveGeneric.cpp 105 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/******************************************************************************
 *
 * This file is part of the Castor project.
 * See http://castor.web.cern.ch/castor
 *
 * Copyright (C) 2003  CERN
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * 
 *
 * @author Castor Dev team, castor-dev@cern.ch
 *****************************************************************************/
Eric Cano's avatar
Eric Cano committed
23

24
25
26
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
#include "castor/tape/tapeserver/drive/FakeDrive.hpp"
#include "castor/tape/tapeserver/drive/DriveGeneric.hpp"
27

Victor Kotlyar's avatar
Victor Kotlyar committed
28
#include "common/Timer.hpp"
29
#include "common/CRC.hpp"
30
#include "common/exception/MemException.hpp"
31

32
33
#include <errno.h>

34
35
#include <string>
#include <map>
Cristina Moraru's avatar
Cristina Moraru committed
36
#include <list>
37

38
39
40
namespace castor {
namespace tape {
namespace tapeserver {
41

42
drive::DriveInterface * drive::createDrive(SCSI::DeviceInfo di, 
43
44
45
    System::virtualWrapper& sw) {
  if (std::string::npos != di.product.find("T10000")) {
    return new DriveT10000(di, sw);
Victor Kotlyar's avatar
Victor Kotlyar committed
46
  } else if (std::string::npos != di.product.find("ULT") || std::string::npos != di.product.find("Ultrium")) {
47
48
49
    return new DriveLTO(di, sw);
  } else if (std::string::npos != di.product.find("03592")) {
    return new DriveIBM3592(di, sw);
50
51
  } else if (std::string::npos != di.product.find("MHVTL")) {
    return new DriveMHVTL(di, sw);
52
  } else if (std::string::npos != di.product.find("VIRTUAL")) {
53
54
    /* In case of a VIRTUAL drive, it could have been pre-allocated 
     * for testing purposes (with "pre-cooked" contents). */
55
    drive::DriveInterface * ret = sw.getDriveByPath(di.nst_dev);
56
57
58
59
60
    if (ret) {
      return ret;
    } else {
      return new FakeDrive();
    }
61
  } else {
62
    throw cta::exception::Exception(std::string("Unsupported drive type: ") + di.product);
63
64
65
  }
}

66
drive::DriveGeneric::DriveGeneric(SCSI::DeviceInfo di, System::virtualWrapper& sw) : m_SCSIInfo(di),
67
m_tapeFD(-1),  m_sysWrapper(sw), m_lbpToUse(lbpToUse::disabled) {
68
69
70
71
  /* Open the device files */
  /* We open the tape device file non-blocking as blocking open on rewind tapes (at least)
   * will fail after a long timeout when no tape is present (at least with mhvtl) 
   */
72
  cta::exception::Errnum::throwOnMinusOne(
73
74
      m_tapeFD = m_sysWrapper.open(m_SCSIInfo.nst_dev.c_str(), O_RDWR | O_NONBLOCK),
      std::string("Could not open device file: ") + m_SCSIInfo.nst_dev);
75
76
}

77
void drive::DriveIBM3592::clearCompressionStats()  {
78
79
80
  SCSI::Structures::logSelectCDB_t cdb;
  cdb.PCR = 1; /* PCR set */
  cdb.PC = 0x3; /* PC = 11b  for T10000 only*/
81
  cdb.pageCode = SCSI::logSensePages::blockBytesTransferred;
82
83
84
85
86
87
88
89
90

  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;

  sgh.setCDB(&cdb);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_NONE;

  /* Manage both system error and SCSI errors. */
91
  cta::exception::Errnum::throwOnMinusOne(
92
93
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::clearCompressionStats");
94
95
96
  SCSI::ExceptionLauncher(sgh, "SCSI error in clearCompressionStats:");
}

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
void drive::DriveT10000::clearCompressionStats() {
  m_compressionStatsBase = getCompressionStats();
}

void drive::DriveLTO::clearCompressionStats() {
  SCSI::Structures::logSelectCDB_t cdb;
  cdb.PCR = 1; /* PCR set */
  cdb.PC = 0x3; /* PC = 11b  for T10000 only*/
  cdb.pageCode = SCSI::logSensePages::dataCompression32h;

  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;

  sgh.setCDB(&cdb);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_NONE;

  /* Manage both system error and SCSI errors. */
  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveGeneric::clearCompressionStats");
  SCSI::ExceptionLauncher(sgh, "SCSI error in clearCompressionStats:");
}

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
std::vector<castor::tape::tapeserver::drive::endOfWrapPosition> drive::DriveLTO::getEndOfWrapPositions() {
  std::vector<castor::tape::tapeserver::drive::endOfWrapPosition> ret;
  
  SCSI::Structures::readEndOfWrapPositionCDB_t cdb;
  //WrapNumbeValid = 0, ReportAll = 1 and WrapNumber = 0 as we want all the end of wraps positions
  cdb.WNV = 0;
  cdb.RA = 1;
  cdb.wrapNumber = 0;
  //Each wrap descriptor is 12 bytes
  SCSI::Structures::setU32(cdb.allocationLength,12 * castor::tape::SCSI::maxLTOTapeWraps);
  
  SCSI::Structures::readEndOfWrapPositionDataLongForm_t data;
  
  SCSI::Structures::LinuxSGIO_t sgh;
  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&data);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;
  
   /* Manage both system error and SCSI errors. */
  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveLTO::getEndOfWrapPositions");
  SCSI::ExceptionLauncher(sgh, "SCSI error in getEndOfWrapPositions:");
  
  int nbWrapReturned = data.getNbWrapsReturned();
  //Loop over the list of wraps of the tape returned by the drive
  for(int i = 0; i < nbWrapReturned; ++i){
    castor::tape::tapeserver::drive::endOfWrapPosition position;
    auto wrapDescriptor = data.wrapDescriptor[i];
    position.wrapNumber = SCSI::Structures::toU16(wrapDescriptor.wrapNumber);
    position.partition = SCSI::Structures::toU16(wrapDescriptor.partition);
    //blockId returned is 6*8 = 48 bytes, so we need to store it into a uint64_t
    position.blockId = SCSI::Structures::toU64(wrapDescriptor.logicalObjectIdentifier);
    ret.push_back(position);
  }
  return ret;
}

159
160
161
162
163
164
165
void drive::DriveLTO::queryRAO(std::list<SCSI::Structures::RAO::blockLims>& files, int maxSupported, const std::string & raoAlgorithm) {
  //TODO : Create an interface RAOAlgorithm with a method called getRAO() taking the files list as input/output parameter
  //Implement this method in three different classes : LinearRAOAlgorithm, RandomRAOAlgorithm, CERNRAOAlgorithm (or another name)
  //Create a factory to return the correct implementation subclass regarding the raoAlgorithm string parameter.
  //Call of that in this method
}

166
167
168
169
/**
 * Information about the drive. The vendor id is used in the user labels of the files.
 * @return    The deviceInfo structure with the information about the drive.
 */
170
drive::deviceInfo drive::DriveGeneric::getDeviceInfo()  {
171
172
173
174
175
176
  SCSI::Structures::inquiryCDB_t cdb;
  SCSI::Structures::inquiryData_t inquiryData;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;
  deviceInfo devInfo;

177
178
  SCSI::Structures::setU16(cdb.allocationLength, sizeof(inquiryData));
  
179
180
181
182
183
184
  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&inquiryData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  /* Manage both system error and SCSI errors. */
185
  cta::exception::Errnum::throwOnMinusOne(
186
187
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::getDeviceInfo");
188
  SCSI::ExceptionLauncher(sgh, "SCSI error in getDeviceInfo:");
189
190
191
192
193

  devInfo.product = SCSI::Structures::toString(inquiryData.prodId);
  devInfo.productRevisionLevel = SCSI::Structures::toString(inquiryData.prodRevLvl);
  devInfo.vendor = SCSI::Structures::toString(inquiryData.T10Vendor);
  devInfo.serialNumber = getSerialNumber();
194
  devInfo.isPIsupported = inquiryData.protect;
195
196
197
  return devInfo;
}

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
drive::deviceInfo drive::DriveT10000::getDeviceInfo()  {
  SCSI::Structures::inquiryCDB_t cdb;
  SCSI::Structures::inquiryData_t inquiryData;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;
  deviceInfo devInfo;

  SCSI::Structures::setU16(cdb.allocationLength, sizeof(inquiryData));

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&inquiryData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  /* Manage both system error and SCSI errors. */
  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveT10000::getDeviceInfo");
  SCSI::ExceptionLauncher(sgh, "SCSI error in getDeviceInfo:");

  devInfo.product = SCSI::Structures::toString(inquiryData.prodId);
  std::string productRevisionMinor = SCSI::Structures::toString(inquiryData.vendorSpecific1).substr(0,4);
  devInfo.productRevisionLevel = SCSI::Structures::toString(inquiryData.prodRevLvl) + productRevisionMinor;
  devInfo.vendor = SCSI::Structures::toString(inquiryData.T10Vendor);
  devInfo.serialNumber = getSerialNumber();
  devInfo.isPIsupported = inquiryData.protect;
  return devInfo;
}

drive::deviceInfo drive::DriveMHVTL::getDeviceInfo()  {
  SCSI::Structures::inquiryCDB_t cdb;
  SCSI::Structures::inquiryData_t inquiryData;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;
  deviceInfo devInfo;

  SCSI::Structures::setU16(cdb.allocationLength, sizeof(inquiryData));

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&inquiryData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  /* Manage both system error and SCSI errors. */
  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveMHVTL::getDeviceInfo");
  SCSI::ExceptionLauncher(sgh, "SCSI error in getDeviceInfo:");

  devInfo.product = SCSI::Structures::toString(inquiryData.prodId);
  devInfo.productRevisionLevel = SCSI::Structures::toString(inquiryData.prodRevLvl);
  devInfo.vendor = SCSI::Structures::toString(inquiryData.T10Vendor);
  devInfo.serialNumber = getSerialNumber();
  devInfo.isPIsupported = inquiryData.protect;
  return devInfo;
}

255
256
257
258
259
260
261
262
263
264
SCSI::Structures::RAO::udsLimits drive::DriveMHVTL::getLimitUDS(){
  SCSI::Structures::RAO::udsLimits lims;
  //For MHVTL and for tests, assume that
  //the max number of files for RAO supported by an MHVTL drive 
  //is 1000;
  lims.maxSize = 1000;
  lims.maxSupported = 1000;
  return lims;
}

265
void drive::DriveMHVTL::queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported, const std::string & raoAlgorithm){
266
267
268
269
  //The query RAO method of MHVTL drive returns nothing
  //something could be implemented for testing...
}

270
271
272
273
274
275
276
277
/**
 * Generic SCSI path, used for passing to external scripts.
 * @return    Path to the generic SCSI device file.
 */
std::string drive::DriveGeneric::getGenericSCSIPath() {
  return m_SCSIInfo.sg_dev;
}

278
279
280
281
/**
 * Information about the serial number of the drive. 
 * @return   Right-aligned ASCII data for the vendor-assigned serial number.
 */
282
std::string drive::DriveGeneric::getSerialNumber()  {
283
284
285
286
287
288
289
  SCSI::Structures::inquiryCDB_t cdb;
  SCSI::Structures::inquiryUnitSerialNumberData_t inquirySerialData;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;

  cdb.EVPD = 1; /* Enable Vital Product Data */
  cdb.pageCode = SCSI::inquiryVPDPages::unitSerialNumber;
290
  SCSI::Structures::setU16(cdb.allocationLength, sizeof(inquirySerialData));
291
292
293
294
295
296
297

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&inquirySerialData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  /* Manage both system error and SCSI errors. */
298
  cta::exception::Errnum::throwOnMinusOne(
299
300
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::getSerialNumber");
301
  SCSI::ExceptionLauncher(sgh, "SCSI error in getSerialNumber:");
302
303
304
305
306
307
308
309
310
311
312
313
314
  std::string serialNumber;
  serialNumber.append(inquirySerialData.productSerialNumber, inquirySerialData.pageLength);

  return serialNumber;
}

/**
 * Position to logical object identifier (i.e. block address). 
 * This function is blocking: the immediate bit is not set.
 * The device server will not return status until the locate operation
 * has completed.
 * @param blockId The blockId, represented in local endianness.
 */
315
void drive::DriveGeneric::positionToLogicalObject(uint32_t blockId)
316
 {
317
318
  SCSI::Structures::locate10CDB_t cdb;
  SCSI::Structures::senseData_t<255> senseBuff;
319
320
321
  SCSI::Structures::LinuxSGIO_t sgh; 
  
  SCSI::Structures::setU32(cdb.logicalObjectID, blockId);
322
323
324
325

  sgh.setCDB(&cdb);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_NONE;
326
  //sgh.timeout = defaultTimeout; // set globally by SCSI::Structures.hpp (defaultTimeout)
327
328

  /* Manage both system error and SCSI errors. */
329
  cta::exception::Errnum::throwOnMinusOne(
330
331
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::positionToLogicalObject");
332
333
334
335
336
337
338
339
340
  SCSI::ExceptionLauncher(sgh, "SCSI error in positionToLogicalObject:");
}

/**
 * Return logical position of the drive. This is the address of the next object
 * to read or write.
 * @return positionInfo class. This contains the logical position, plus information
 * on the dirty data still in the write buffer.
 */
341
drive::positionInfo drive::DriveGeneric::getPositionInfo()
342
 {
343
344
345
346
347
348
  SCSI::Structures::readPositionCDB_t cdb;
  SCSI::Structures::readPositionDataShortForm_t positionData;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;

  positionInfo posInfo;
349
  
350
351
352
  // We just go all defaults: service action = 00 (SHORT FORM BLOCK ID)
  // The result will come in fixed size and allocation length must be 0.
  // At least IBM drives will complain otherwise
353
  
354
355
356
357
358
359
  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&positionData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  /* Manage both system error and SCSI errors. */
360
  cta::exception::Errnum::throwOnMinusOne(
361
362
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::getPositionInfo");
363
  SCSI::ExceptionLauncher(sgh, "SCSI error in getPositionInfo:");
364
365
366
367
368
369
370
371
372
373
374
375
376

  if (0 == positionData.PERR) { // Location fields are valid
    posInfo.currentPosition = SCSI::Structures::toU32(positionData.firstBlockLocation);
    posInfo.oldestDirtyObject = SCSI::Structures::toU32(positionData.lastBlockLocation);
    posInfo.dirtyObjectsCount = SCSI::Structures::toU32(positionData.blocksInBuffer);
    posInfo.dirtyBytesCount = SCSI::Structures::toU32(positionData.bytesInBuffer);
  } else {
    /* An overflow has occurred in at least one of the returned position
     * data fields. The application should use the LONG FORM to obtain the 
     * current position or the application should use the EXTENDED FORM to
     * obtain the current position and number of bytes in the object buffer.
     * (note) For T10000 we have only SHORT FORM.
     */
377
    throw cta::exception::Exception(std::string("An overflow has occurred in getPostitionInfo"));
378
379
380
381
  }
  return posInfo;
}

382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
/**
 * Return physical position of the drive.
 *
 * @return physicalPositionInfo class. This contains the wrap and linear position (LPOS).
 */
drive::physicalPositionInfo drive::DriveGeneric::getPhysicalPositionInfo()
{
  SCSI::Structures::requestSenseCDB_t cdb;
  SCSI::Structures::requestSenseData_t requestSenseData;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;

  // The full Request Sense data record is 96 bytes. However, we are only interested in
  // the PHYSICAL WRAP and LPOS fields (bytes 29-33) so we can discard the rest.
  cdb.allocationLength = 34;

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&requestSenseData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  // Manage both system error and SCSI errors
  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveGeneric::getPhysicalPositionInfo");
  SCSI::ExceptionLauncher(sgh, "SCSI error in getPhysicalPositionInfo:");

  physicalPositionInfo posInfo;
  posInfo.wrap = requestSenseData.physicalWrap;
  posInfo.lpos = SCSI::Structures::toU32(requestSenseData.relativeLPOSValue);
  return posInfo;
}

415
416
417
418
419
420
421
422
423
/**
* Returns all the end of wrap positions of the mounted tape
* 
* @return a vector of endOfWrapsPositions. 
*/
std::vector<drive::endOfWrapPosition> drive::DriveGeneric::getEndOfWrapPositions() {
  return std::vector<drive::endOfWrapPosition>();
}

424
425
/**
 * Get tape alert information from the drive. There is a quite long list of possible tape alerts.
Eric Cano's avatar
Eric Cano committed
426
 * They are described in SSC-4, section 4.2.20: TapeAlert application client interface.
427
428
 * Section is 4.2.17 in SSC-3. This version gives a list of numerical codes.
 * @return list of tape alerts codes.
429
 */
430
std::vector<uint16_t> drive::DriveGeneric::getTapeAlertCodes(){
431
  /* return vector */
432
  std::vector<uint16_t> ret;
433
434
435
436
437
  /* We don't know how many elements we'll get. Prepare a 100 parameters array */
  SCSI::Structures::tapeAlertLogPage_t<100> tal;
  /* Prepare a sense buffer of 255 bytes */
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::logSenseCDB_t cdb;
438
439
  SCSI::Structures::LinuxSGIO_t sgh;
  
440
  cdb.pageCode = SCSI::logSensePages::tapeAlert;
Eric Cano's avatar
Eric Cano committed
441
  cdb.PC = 0x01; // Current Comulative Values
442
443
  SCSI::Structures::setU16(cdb.allocationLength, sizeof(tal));
  
444
445
446
447
448
  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&tal);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;
  /* Manage both system error and SCSI errors. */
449
  cta::exception::Errnum::throwOnMinusOne(
450
451
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::getTapeAlerts");
452
  SCSI::ExceptionLauncher(sgh, "SCSI error in getTapeAlerts:");
453
454
455
456
457
  /* Return the ACTIVE tape alerts (this is indicated by "flag" (see 
   * SSC-4: 8.2.3 TapeAlert log page). As they are simply used for logging;
   * return strings. */
  for (size_t i = 0; i < tal.parameterNumber(); i++) {
    if (tal.parameters[i].flag)
458
459
460
461
462
463
      ret.push_back(SCSI::Structures::toU16(tal.parameters[i].parameterCode));
  }
  return ret;
}

/**
464
 * Translate  tape alert codes into strings.
465
 */
466
std::vector<std::string> drive::DriveGeneric::getTapeAlerts(const std::vector<uint16_t>& tacs){
467
468
469
  /* return vector */
  std::vector<std::string> ret;
  /* convert tape alert codes to strings */
470
  for (std::vector<uint16_t>::const_iterator code =  tacs.begin(); code!= tacs.end(); code++) {
471
472
473
474
475
476
    ret.push_back(SCSI::tapeAlertToString(*code));
  }
  return ret;
}

/**
477
 * Translate tape alert codes into compact strings.
478
 */
479
std::vector<std::string> drive::DriveGeneric::getTapeAlertsCompact(const std::vector<uint16_t>& tacs){
480
481
482
  /* return vector */
  std::vector<std::string> ret;
  /* convert tape alert codes to strings */
483
  for (std::vector<uint16_t>::const_iterator code =  tacs.begin(); code!= tacs.end(); code++) {
484
    ret.push_back(SCSI::tapeAlertToCompactString(*code));
485
486
487
488
  }
  return ret;
}

489
490
491
492
493
494
495
496
497
498
499
500
501
502
//------------------------------------------------------------------------------
// tapeAlertsCriticalForWrite
//------------------------------------------------------------------------------
bool drive::DriveGeneric::tapeAlertsCriticalForWrite(
  const std::vector<uint16_t> & codes) {
  for (std::vector<uint16_t>::const_iterator code =  codes.begin(); 
    code!= codes.end(); code++) {
      if(SCSI::isTapeAlertCriticalForWrite(*code)) {
        return true;
      }
  }
  return false;
}

503
504
505
506
507
508
509
510
511
512
513
514
515
/**
 * Set the tape density and compression. 
 * We use MODE SENSE/SELECT Device Configuration (10h) mode page.
 * As soon as there is no definition in SPC-4 or SSC-3 it depends on the 
 * drives documentation. 
 * 
 * @param densityCode  The tape specific density code.
 *                     If it is 0 (default) than we use the density code 
 *                     detected by the drive itself means no changes.
 *                                
 * @param compression  The boolean variable to enable or disable compression
 *                     on the drive for the tape. By default it is enabled.
 */
516
void drive::DriveGeneric::setDensityAndCompression(bool compression,
517
    unsigned char densityCode)  {
518
519
520
521
522
523
524
  SCSI::Structures::modeSenseDeviceConfiguration_t devConfig;
  { // get info from the drive
    SCSI::Structures::modeSense6CDB_t cdb;
    SCSI::Structures::senseData_t<255> senseBuff;
    SCSI::Structures::LinuxSGIO_t sgh;

    cdb.pageCode = SCSI::modeSensePages::deviceConfiguration;
525
    cdb.allocationLength = sizeof (devConfig);
526
527
528
529
530
531
532

    sgh.setCDB(&cdb);
    sgh.setDataBuffer(&devConfig);
    sgh.setSenseBuffer(&senseBuff);
    sgh.dxfer_direction = SG_DXFER_FROM_DEV;

    /* Manage both system error and SCSI errors. */
533
    cta::exception::Errnum::throwOnMinusOne(
534
535
        m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
        "Failed SG_IO ioctl in DriveGeneric::setDensityAndCompression");
536
    SCSI::ExceptionLauncher(sgh, "SCSI error in setDensityAndCompression:");
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  }

  { // set parameters and we use filled structure devConfig from the previous SCSI call
    SCSI::Structures::modeSelect6CDB_t cdb;
    SCSI::Structures::senseData_t<255> senseBuff;
    SCSI::Structures::LinuxSGIO_t sgh;

    cdb.PF = 1; // means nothing for IBM, LTO, T10000
    cdb.paramListLength = sizeof (devConfig);

    devConfig.header.modeDataLength = 0; // must be 0 for IBM, LTO ignored by T10000
    if (0 != densityCode) devConfig.blockDescriptor.densityCode = densityCode;
    if (compression) devConfig.modePage.selectDataComprAlgorithm = 1;
    else devConfig.modePage.selectDataComprAlgorithm = 0;

    sgh.setCDB(&cdb);
    sgh.setDataBuffer(&devConfig);
    sgh.setSenseBuffer(&senseBuff);
    sgh.dxfer_direction = SG_DXFER_TO_DEV;

    /* Manage both system error and SCSI errors. */
558
    cta::exception::Errnum::throwOnMinusOne(
559
560
        m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
        "Failed SG_IO ioctl in DriveGeneric::setDensityAndCompression");
561
    SCSI::ExceptionLauncher(sgh, "SCSI error in setDensityAndCompression:");
562
563
564
  }
}

565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
//------------------------------------------------------------------------------
// setLogicalBlockProtection
//------------------------------------------------------------------------------
void drive::DriveGeneric::setLogicalBlockProtection(
  const unsigned char method, const unsigned char methodLength,
  const bool enableLBPforRead, const bool enableLBPforWrite) {

  SCSI::Structures::modeSenseControlDataProtection_t controlDataProtection;
  {
    /* fetch Control Data Protection */
    SCSI::Structures::modeSense6CDB_t cdb;
    SCSI::Structures::senseData_t<255> senseBuff;
    SCSI::Structures::LinuxSGIO_t sgh;

    cdb.pageCode = SCSI::modeSensePages::controlDataProtection;
    cdb.subPageCode = SCSI::modePageControlDataProtection::subpageCode;
    cdb.allocationLength = sizeof (controlDataProtection);

    sgh.setCDB(&cdb);
    sgh.setDataBuffer(&controlDataProtection);
    sgh.setSenseBuffer(&senseBuff);
    sgh.dxfer_direction = SG_DXFER_FROM_DEV;

    /* Manage both system error and SCSI errors. */
589
    cta::exception::Errnum::throwOnMinusOne(
590
591
592
593
594
595
596
597
598
599
600
601
602
      m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl"  );     
    SCSI::ExceptionLauncher(sgh,
      std::string("SCSI error fetching data in setLogicalBlockProtection: ") +
      SCSI::statusToString(sgh.status));
  }

  {
    /* Use the previously fetched page, modify fields and submit it */
    SCSI::Structures::modeSelect6CDB_t cdb;
    SCSI::Structures::senseData_t<255> senseBuff;
    SCSI::Structures::LinuxSGIO_t sgh;

603
604
605
606
607
608
609
    cdb.PF = 1; // means nothing for IBM, LTO, T10000
    cdb.paramListLength = sizeof (controlDataProtection.header) +
      sizeof (controlDataProtection.blockDescriptor) +
      SCSI::controlDataProtectionModePageLengthAddition + 
      SCSI::Structures::toU16(controlDataProtection.modePage.pageLength);    
    if (cdb.paramListLength > sizeof(controlDataProtection)) {
      // should never happen 
610
      throw cta::exception::Exception(
611
612
613
        std::string("cdb.paramListLength greater then size "
                    "of controlDataProtection in setLogicalBlockProtection"));
    }
614
615
616
617
    controlDataProtection.header.modeDataLength = 0; // must be 0 for IBM, LTO 
                                                     // ignored by T10000
    controlDataProtection.modePage.LBPMethod = method;
    controlDataProtection.modePage.LBPInformationLength = methodLength;
618
619
    controlDataProtection.modePage.LBP_W = enableLBPforWrite;
    controlDataProtection.modePage.LBP_R = enableLBPforRead;
620
621
622
623
624
625
626

    sgh.setCDB(&cdb);
    sgh.setDataBuffer(&controlDataProtection);
    sgh.setSenseBuffer(&senseBuff);
    sgh.dxfer_direction = SG_DXFER_TO_DEV;

    /* Manage both system error and SCSI errors. */
627
    cta::exception::Errnum::throwOnMinusOne(   
628
629
630
631
632
633
634
635
636
637
638
639
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl"  );     
    SCSI::ExceptionLauncher(sgh,
            std::string("SCSI error setting data in setDataProtection : ") +
            SCSI::statusToString(sgh.status));
  }
}

//------------------------------------------------------------------------------
// enableCRC32CLogicalBlockProtectionReadOnly
//------------------------------------------------------------------------------
void drive::DriveGeneric::enableCRC32CLogicalBlockProtectionReadOnly() {
640
  m_lbpToUse=lbpToUse::crc32cReadOnly;
641
642
  setLogicalBlockProtection(SCSI::logicBlockProtectionMethod::CRC32C,
    SCSI::logicBlockProtectionMethod::CRC32CLength,true,false);
643
}
Daniele Kruse's avatar
Daniele Kruse committed
644

645
646
647
648
//------------------------------------------------------------------------------
// enableCRC32CLogicalBlockProtectionReadWrite
//------------------------------------------------------------------------------
void drive::DriveGeneric::enableCRC32CLogicalBlockProtectionReadWrite() {
649
  m_lbpToUse=lbpToUse::crc32cReadWrite;
650
651
  setLogicalBlockProtection(SCSI::logicBlockProtectionMethod::CRC32C,
    SCSI::logicBlockProtectionMethod::CRC32CLength,true,true);
652
653
}

654
655
656
657
//------------------------------------------------------------------------------
// disableLogicalBlockProtection
//------------------------------------------------------------------------------
void drive::DriveGeneric::disableLogicalBlockProtection() {
658
  m_lbpToUse=lbpToUse::disabled;
659
660
  setLogicalBlockProtection(0,0,false,false);      
}
661
662
663
664
665
666
667

//------------------------------------------------------------------------------
// getLBPInfo
//------------------------------------------------------------------------------
drive::LBPInfo drive::DriveGeneric::getLBPInfo() {
  SCSI::Structures::modeSenseControlDataProtection_t controlDataProtection;
  drive::LBPInfo LBPdata;
668
  
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  /* fetch Control Data Protection */
  SCSI::Structures::modeSense6CDB_t cdb;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::LinuxSGIO_t sgh;

  cdb.pageCode = SCSI::modeSensePages::controlDataProtection;
  cdb.subPageCode = SCSI::modePageControlDataProtection::subpageCode;
  cdb.allocationLength = sizeof (controlDataProtection);

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&controlDataProtection);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  /* Manage both system error and SCSI errors. */
684
  cta::exception::Errnum::throwOnMinusOne(
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl"  );     
  SCSI::ExceptionLauncher(sgh,
    std::string("SCSI error fetching data in getLBPInfo: ") +
    SCSI::statusToString(sgh.status));

  LBPdata.method = controlDataProtection.modePage.LBPMethod;
  LBPdata.methodLength = controlDataProtection.modePage.LBPInformationLength;  
  LBPdata.enableLBPforRead = (1 == controlDataProtection.modePage.LBP_R);
  LBPdata.enableLBPforWrite = (1 == controlDataProtection.modePage.LBP_W);

  return LBPdata;
}

699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
//------------------------------------------------------------------------------
// Encryption interface
//------------------------------------------------------------------------------
void drive::DriveGeneric::setEncryptionKey(const std::string &encryption_key) {
  if(!isEncryptionCapEnabled())
    throw cta::exception::Exception("In DriveGeneric::setEncryptionKey: Tried to enable encryption on drive "
                                    "without encryption capabilities enabled.");
  if (encryption_key.empty())
    clearEncryptionKey();
  else {
    SCSI::Structures::LinuxSGIO_t sgh;
    SCSI::Structures::encryption::spoutCDB_t cdb;
    SCSI::Structures::senseData_t<255> senseBuff;
    SCSI::Structures::encryption::spoutSDEParam_t sps;

    SCSI::Structures::setU16(sps.pageCode, SCSI::encryption::spoutSecurityProtocolSpecificPages::setDataEncryptionPage);
    /*
     * Length is size of the spoutSDEParam_t - (sizeof(sps.pageCode) + sizeof(sps.length))
     */
    SCSI::Structures::setU16(sps.length, sizeof(SCSI::Structures::encryption::spoutSDEParam_t) - 4);

    sps.nexusScope = SCSI::encryption::encryptionNexusScopes::scopeLocal; // oracle compatibility
    sps.encryptionMode = SCSI::encryption::encryptionModes::modeEncrypt;
    sps.decryptionMode = SCSI::encryption::decryptionModes::modeMixed;
    sps.algorithmIndex = 0x01;
    sps.keyFormat = SCSI::encryption::keyFormatTypes::keyFormatNormal;
    strncpy((char *)sps.keyData, encryption_key.c_str(), SCSI::encryption::ENC_KEY_LENGTH);
    /*
     * This means that if the key given is smaller, it's right padded with zeros.
     * If the key given is bigger, we the first 256-bit are used.
     */

    cdb.securityProtocol = SCSI::encryption::spoutSecurityProtocolPages::tapeDataEncryption;
    SCSI::Structures::setU16(cdb.securityProtocolSpecific,
                             SCSI::encryption::spoutSecurityProtocolSpecificPages::setDataEncryptionPage);
    SCSI::Structures::setU32(cdb.allocationLength, sizeof(SCSI::Structures::encryption::spoutSDEParam_t));

    sgh.setCDB(&cdb);
    sgh.setDataBuffer(&sps);
    sgh.setSenseBuffer(&senseBuff);
    sgh.dxfer_direction = SG_DXFER_TO_DEV;

    cta::exception::Errnum::throwOnMinusOne(
      m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
      "Failed SG_IO ioctl in DriveGeneric::setEncryptionKey");
    SCSI::ExceptionLauncher(sgh, "SCSI error in DriveGeneric::setEncryptionKey");
  }
}

bool drive::DriveGeneric::clearEncryptionKey() {
  if (!isEncryptionCapEnabled())
    return false;
  SCSI::Structures::LinuxSGIO_t sgh;
  SCSI::Structures::encryption::spoutCDB_t cdb;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::encryption::spoutSDEParam_t sps;

  SCSI::Structures::setU16(sps.pageCode, SCSI::encryption::spoutSecurityProtocolSpecificPages::setDataEncryptionPage);

  sps.nexusScope = SCSI::encryption::encryptionNexusScopes::scopeLocal; // oracle compatibility
  sps.encryptionMode = SCSI::encryption::encryptionModes::modeDisable;
  sps.decryptionMode = SCSI::encryption::decryptionModes::modeDisable;
  sps.algorithmIndex = 0x01;
  sps.keyFormat = SCSI::encryption::keyFormatTypes::keyFormatNormal;

  /*
   * Length is size of the spoutSDEParam_t - (sizeof(sps.pageCode) + sizeof(sps.length))
   */
  SCSI::Structures::setU16(sps.length, sizeof(SCSI::Structures::encryption::spoutSDEParam_t) - 4);

  cdb.securityProtocol = SCSI::encryption::spoutSecurityProtocolPages::tapeDataEncryption;
  SCSI::Structures::setU16(cdb.securityProtocolSpecific, SCSI::encryption::spoutSecurityProtocolSpecificPages::setDataEncryptionPage);
  SCSI::Structures::setU32(cdb.allocationLength, sizeof(SCSI::Structures::encryption::spoutSDEParam_t));


  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&sps);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_TO_DEV;

  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveGeneric::clearEncryptionKey");
  SCSI::ExceptionLauncher(sgh, "SCSI error in DriveGeneric::clearEncryptionKey");
  return true;
}

bool drive::DriveGeneric::isEncryptionCapEnabled() {
  return false;
}

bool drive::DriveIBM3592::isEncryptionCapEnabled() {
  /*
   * We are acquiring the encryption capability from the length of the SPIN index page.
   * If it has one page (only 0x00), then encryption is disabled from the libary.
   * If it has more pages, the encryption(0x00, 0x20 at the moment of writing), then it is enabled.
   */
  SCSI::Structures::LinuxSGIO_t sgh;
  SCSI::Structures::encryption::spinCDB_t cdb;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::encryption::spinPageList_t<20> pl;

  cdb.securityProtocol = SCSI::encryption::spinSecurityProtocolPages::securityProtocolInformation;
  SCSI::Structures::setU16(cdb.securityProtocolSpecific, 0x0000);
  SCSI::Structures::setU32(cdb.allocationLength, sizeof(pl));

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&pl);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveIBM3592::isEncryptionCapEnabled");
  SCSI::ExceptionLauncher(sgh, "SCSI error in DriveIBM3592::clearEncryptionKey");

  return SCSI::Structures::toU16(pl.supportedProtocolListLength) > 1;
}

bool drive::DriveT10000::isEncryptionCapEnabled() {
  /*
   * We are acquiring the encryption capability from the inquiry page on Oracle T10k drives
   * because the SPIN index page is not available when encryption is disabled from
   * the Oracle libary interface (invalid cdb error).
   */
  SCSI::Structures::LinuxSGIO_t sgh;
  SCSI::Structures::inquiryCDB_t cdb;
  SCSI::Structures::senseData_t<255> senseBuff;
  SCSI::Structures::inquiryDataT10k_t inqData;

  // EVPD and page code set to zero => standard inquiry
  SCSI::Structures::setU16(cdb.allocationLength, sizeof(inqData));

  sgh.setCDB(&cdb);
  sgh.setDataBuffer(&inqData);
  sgh.setSenseBuffer(&senseBuff);
  sgh.dxfer_direction = SG_DXFER_FROM_DEV;

  cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
    "Failed SG_IO ioctl in DriveT10000::isEncryptionCapEnabled");
  SCSI::ExceptionLauncher(sgh, "SCSI error in DriveT10000::clearEncryptionKey");

  unsigned char keyManagement = inqData.keyMgmt; // oracle metric for key management

  return keyManagement != 0x0;
}

void drive::DriveMHVTL::setEncryptionKey(const std::string &encryption_key) {
  throw cta::exception::Exception("In DriveMHVTL::setEncryptionKey: Encryption cannot be enabled.");
}

bool drive::DriveMHVTL::clearEncryptionKey() {
  return false;
}

bool drive::DriveMHVTL::isEncryptionCapEnabled() {
  return false;
}

Cristina Moraru's avatar
Cristina Moraru committed
859
SCSI::Structures::RAO::udsLimits drive::DriveGeneric::getLimitUDS() {
860
861
862
    SCSI::Structures::LinuxSGIO_t sgh;
    SCSI::Structures::RAO::recieveRAO_t cdb;
    SCSI::Structures::senseData_t<127> senseBuff;
Cristina Moraru's avatar
Cristina Moraru committed
863
864
    SCSI::Structures::RAO::udsLimitsPage_t limitsSCSI;
    SCSI::Structures::RAO::udsLimits lims;
865

Cristina Moraru's avatar
Cristina Moraru committed
866
    cdb.serviceAction = 0x1d;
867
    cdb.udsLimits = 1;
Cristina Moraru's avatar
Cristina Moraru committed
868
    SCSI::Structures::setU32(cdb.allocationLength, sizeof(SCSI::Structures::RAO::udsLimitsPage_t));
Cristina Moraru's avatar
Cristina Moraru committed
869
    
870
871
    sgh.setCDB(&cdb);
    sgh.setSenseBuffer(&senseBuff);
Cristina Moraru's avatar
Cristina Moraru committed
872
    sgh.setDataBuffer(&limitsSCSI);
873
874
875
876
877
878
879
880
    sgh.dxfer_direction = SG_DXFER_FROM_DEV;

    /* Manage both system error and SCSI errors. */
    cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
            "Failed SG_IO ioctl in DriveGeneric::getLimitUDS");
    SCSI::ExceptionLauncher(sgh, "SCSI error in DriveGeneric::getLimitUDS");

Cristina Moraru's avatar
Cristina Moraru committed
881
882
883
884
    lims.maxSupported = SCSI::Structures::toU16(limitsSCSI.maxSupported);
    lims.maxSize = SCSI::Structures::toU16(limitsSCSI.maxSize);

    return lims;
885
886
}

Cristina Moraru's avatar
Cristina Moraru committed
887
888
void drive::DriveGeneric::generateRAO(std::list<SCSI::Structures::RAO::blockLims> &files,
                                      int maxSupported) {
889
890
891
892
    SCSI::Structures::LinuxSGIO_t sgh;
    SCSI::Structures::RAO::generateRAO_t cdb;
    SCSI::Structures::senseData_t<127> senseBuff;

Cristina Moraru's avatar
Cristina Moraru committed
893
894
    int udSize = std::min((int) files.size(), maxSupported);
    
895
    std::unique_ptr<SCSI::Structures::RAO::udsDescriptor_t[]>  ud (new SCSI::Structures::RAO::udsDescriptor_t[udSize]());
Cristina Moraru's avatar
Cristina Moraru committed
896
897
898
899
900
901
    
    auto it = files.begin();
    for (int i = 0; i < udSize; ++i) {
      strncpy((char*)ud.get()[i].udsName, (char*)it->fseq, 10);
      SCSI::Structures::setU64(ud.get()[i].beginLogicalObjID, it->begin);
      SCSI::Structures::setU64(ud.get()[i].endLogicalObjID, it->end);
902
903
904
905
      ++it;
    }

    SCSI::Structures::RAO::generateRAOParams_t params;
906
    int real_params_len = sizeof(params) + (udSize - 1) *
907
908
                          sizeof(SCSI::Structures::RAO::udsDescriptor_t);
    std::unique_ptr<unsigned char[]>  dataBuff (new unsigned char[real_params_len]());
909

Cristina Moraru's avatar
Cristina Moraru committed
910
    cdb.serviceAction = 0x1d;
911
912

    SCSI::Structures::setU32(cdb.paramsListLength, real_params_len);
913
914
915
    SCSI::Structures::setU32(params.udsListLength, udSize * sizeof(SCSI::Structures::RAO::udsDescriptor_t));
    memcpy(dataBuff.get(), &params, 8); // copy first 2 fields
    memcpy(dataBuff.get() + 8, ud.get(), udSize * sizeof(SCSI::Structures::RAO::udsDescriptor_t));
916
917
918
    
    sgh.setCDB(&cdb);
    sgh.setSenseBuffer(&senseBuff);
Cristina Moraru's avatar
Cristina Moraru committed
919
    sgh.setDataBuffer(dataBuff.get(), real_params_len);
920
921
922
923
924
925
926
927
928
    sgh.dxfer_direction = SG_DXFER_TO_DEV;

    /* Manage both system error and SCSI errors. */
    cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
            "Failed SG_IO ioctl in DriveGeneric::requestRAO");
    SCSI::ExceptionLauncher(sgh, "SCSI error in DriveGeneric::requestRAO");
}

Cristina Moraru's avatar
Cristina Moraru committed
929
void drive::DriveGeneric::receiveRAO(std::list<SCSI::Structures::RAO::blockLims> &files) {
930
931
932
    SCSI::Structures::LinuxSGIO_t sgh;
    SCSI::Structures::RAO::recieveRAO_t cdb;
    SCSI::Structures::senseData_t<255> senseBuff;
933
934
935
936
937
938
939
    SCSI::Structures::RAO::raoList_t *params;

    int udSize = files.size();
    int real_params_len = sizeof(SCSI::Structures::RAO::raoList_t) + (udSize - 1) *
                          sizeof(SCSI::Structures::RAO::udsDescriptor_t);
    std::unique_ptr<unsigned char[]>  dataBuff (new unsigned char[real_params_len]());
    memset(dataBuff.get(), 0, real_params_len);
940
941

    cdb.udsLimits = 0;
Cristina Moraru's avatar
Cristina Moraru committed
942
    cdb.serviceAction = 0x1d;
943

Cristina Moraru's avatar
Cristina Moraru committed
944
    SCSI::Structures::setU32(cdb.allocationLength, real_params_len);
945
946
947

    sgh.setCDB(&cdb);
    sgh.setSenseBuffer(&senseBuff);
Cristina Moraru's avatar
Cristina Moraru committed
948
    sgh.setDataBuffer(dataBuff.get(), real_params_len);
949
950
951
952
953
954
955
956
    sgh.dxfer_direction = SG_DXFER_FROM_DEV;

    /* Manage both system error and SCSI errors. */
    cta::exception::Errnum::throwOnMinusOne(
    m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh),
            "Failed SG_IO ioctl in DriveGeneric::getRAO");
    SCSI::ExceptionLauncher(sgh, "SCSI error in DriveGeneric::getRAO");

957
    params = (SCSI::Structures::RAO::raoList_t *) dataBuff.get();
958

959
960
961
962
963
    files.clear();
    uint32_t desc_list_len = SCSI::Structures::toU32(params->raoDescriptorListLength);
    int files_no = desc_list_len / sizeof(SCSI::Structures::RAO::udsDescriptor_t);
    SCSI::Structures::RAO::udsDescriptor_t *ud = params->udsDescriptors;
    while (files_no > 0) {
964
        SCSI::Structures::RAO::blockLims bl;
965
966
967
        strncpy((char*)bl.fseq, (char*)ud->udsName, 10);
        bl.begin = SCSI::Structures::toU64(ud->beginLogicalObjID);
        bl.end = SCSI::Structures::toU64(ud->endLogicalObjID);
968
        files.emplace_back(bl);
969
970
        ud++;
        files_no--;
971
972
973
    }
}

974
void drive::DriveGeneric::queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files,
975
                                   int maxSupported, const std::string & raoAlgorithm) {
976
    generateRAO(files, maxSupported);
Cristina Moraru's avatar
Cristina Moraru committed
977
    receiveRAO(files);
978
979
}

Daniele Kruse's avatar
Daniele Kruse committed
980
981
982
983
/**
 * Function that checks if a tape is blank (contains no records) 
 * @return true if tape is blank, false otherwise
 */      
984
bool drive::DriveGeneric::isTapeBlank() {
Daniele Kruse's avatar
Daniele Kruse committed
985
986
987
988
989
990
991
992
  struct mtop mtCmd1;
  mtCmd1.mt_op = MTREW;
  mtCmd1.mt_count = 1;
  
  struct mtop mtCmd2;
  mtCmd2.mt_op = MTFSR;
  mtCmd2.mt_count = 1;
 
993
994
  struct mtget mtInfo;
  
995
996
  if((0 == m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &mtCmd1)) && (0 != m_sysWrapper.ioctl(m_tapeFD, MTIOCTOP, &mtCmd2))) {
    //we are doing it the old CASTOR way (see readlbl.c)
997
998
    if(m_sysWrapper.ioctl(m_tapeFD, MTIOCGET, &mtInfo)>=0) {
      if(GMT_EOD(mtInfo.mt_gstat) && GMT_BOT(mtInfo.mt_gstat)) {
Daniele Kruse's avatar
Daniele Kruse committed
999
1000
        return true;
      }
For faster browsing, not all history is shown. View entire blame