scsiprint.cpp 12.8 KB
Newer Older
ballen4705's avatar
ballen4705 committed
1
2
3
/*
 * scsiprint.c
 *
4
5
 * Home page of code is: http://smartmontools.sourceforge.net
 *
ballen4705's avatar
ballen4705 committed
6
 * Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
ballen4705's avatar
ballen4705 committed
7
8
9
10
11
12
13
14
15
16
 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
 *
 * 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, or (at your option)
 * any later version.
 *
 * You should have received a copy of the GNU General Public License
 * (for example COPYING); if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
ballen4705's avatar
ballen4705 committed
17
18
19
20
21
22
 *
 * This code was originally developed as a Senior Thesis by Michael Cornwell
 * at the Concurrent Systems Laboratory (now part of the Storage Systems
 * Research Center), Jack Baskin School of Engineering, University of
 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
 *
ballen4705's avatar
ballen4705 committed
23
24
25
26
27
28
29
30
31
 */


#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

32
#include "extern.h"
ballen4705's avatar
ballen4705 committed
33
34
#include "scsicmds.h"
#include "scsiprint.h"
35
36
#include "smartctl.h"
#include "utility.h"
ballen4705's avatar
ballen4705 committed
37
38
39

#define GBUF_SIZE 65535

40
41
const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.19 2003/01/16 15:28:57 ballen4705 Exp $"
EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
42

43
44
45
// control block which points to external global control variables
extern atamainctrl *con;

ballen4705's avatar
ballen4705 committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
UINT8 gBuf[GBUF_SIZE];

UINT8 gSmartPage = 0;
UINT8 gTempPage = 0;
UINT8 gSelfTestPage = 0;
UINT8 gStartStopPage = 0;
UINT8 gTapeAlertsPage = 0;





void scsiGetSupportPages ( int device)
{
   int i;

   if (logsense ( device , SUPPORT_LOG_PAGES, (UINT8 *) &gBuf) != 0)
   {
       perror ( "Log Sense failed"); 
       exit (1);
   } 

   for ( i = 4; i < gBuf[3] + LOGPAGEHDRSIZE ; i++)
   {
      switch ( gBuf[i])
      {
         case TEMPERATURE_PAGE:
            gTempPage = 1;
            break;
         case STARTSTOP_CYCLE_COUNTER_PAGE:
            gStartStopPage = 1;
            break;
         case SELFTEST_RESULTS_PAGE:
            gSelfTestPage = 1;
            break;
         case SMART_PAGE:
            gSmartPage = 1;
            break;
         case TAPE_ALERTS_PAGE:
            gTapeAlertsPage = 1;
            break;
         default:
            break;

       }
   }
}

void scsiGetSmartData (int device)
{

   UINT8 returnvalue;
   UINT8 currenttemp;
   UINT8 triptemp;

   if ( scsiCheckSmart(device, gSmartPage, 
                       &returnvalue, &currenttemp, &triptemp ) != 0)
   {
      perror ( "scsiGetSmartData Failed");
      exit (1);
   }
	
   if ( returnvalue )
      printf("S.M.A.R.T. Sense: (%02x) %s\n", (UINT8) returnvalue, 
                scsiSmartGetSenseCode(returnvalue));
   else
ballen4705's avatar
ballen4705 committed
112
      printf("S.M.A.R.T. Sense: Ok!\n");
ballen4705's avatar
ballen4705 committed
113
114
115
116
117
118
119
120
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

   if ( (currenttemp || triptemp) && !gTempPage)
   {
      printf("Current Drive Temperature:     %d C\n", currenttemp);
      printf("Drive Trip Temperature:        %d C\n", triptemp);
   }
}


void scsiGetTapeAlertsData (int device)
{
    unsigned short pagelength;
    unsigned short parametercode;
    int i;
    int failure = 0;

    if ( logsense( device, TAPE_ALERTS_PAGE, (UINT8 *) &gBuf) != 0)
    {
   	     perror ( "scsiGetSmartData Failed");
	     exit (1);
    }

    if ( gBuf[0] != 0x2e )
    {
         printf("TapeAlerts Log Sense Failed\n");
         exit(-1);
    }

    pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3];

    for ( i = 4; i < pagelength;i+=5 )
    {
        parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1];

        if (gBuf[i+4])
        {
           printf("Tape Alerts Error!!!\n%s\n",
              scsiTapeAlertsTapeDevice(parametercode));
           failure = 1; 
        }          
    }

    if(!failure)
      printf("No Tape Alerts Failure\n");

}

void scsiGetStartStopData ( int device)
{
    UINT32 currentStartStop;
    UINT32 recommendedStartStop; 

    if ( logsense( device, STARTSTOP_CYCLE_COUNTER_PAGE, (UINT8 *) &gBuf) != 0)
    {
   	     perror ( "scsiGetStartStopData Failed");
	     exit (1);
    }


    if ( gBuf[0] != STARTSTOP_CYCLE_COUNTER_PAGE )
    {
         printf("StartStop Log Sense Failed\n");
         exit(-1);
    }


179
180
181
182
    recommendedStartStop= (UINT32) gBuf[28]<< 24 | gBuf[29] << 16 |
                                       gBuf[30] << 8 | gBuf[31];
    currentStartStop= (UINT32) gBuf[36]<< 24 | gBuf[37] << 16 |
                                       gBuf[38] << 8 | gBuf[39];
ballen4705's avatar
ballen4705 committed
183
184
185
186
187

    printf("Current start stop count:      %u times\n", currentStartStop);
    printf("Recommended start stop count:  %u times\n", recommendedStartStop);
} 

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
const char * self_test_code[] = {
        "Default         ", 
	"Background short", 
	"Background long ", 
	"Reserved(3)     ",
	"Abort background", 
	"Foreground short", 
	"Foreground long ",
	"Reserved(7)     "
};

const char * self_test_result[] = {
        "Completed                ",
	"Interrupted ('-X' switch)",
	"Interrupted (bus reset ?)",
	"Unknown error, incomplete",
	"Completed, segment failed",
	"Failed in first segment  ",
	"Failed in second segment ",
	"Failed in segment -->    ",
	"Reserved(8)              ", 
	"Reserved(9)              ", 
	"Reserved(10)             ", 
	"Reserved(11)             ", 
	"Reserved(12)             ", 
	"Reserved(13)             ", 
	"Reserved(14)             ",
	"Self test in progress ..."
};

ballen4705's avatar
ballen4705 committed
218
219
// See Working Draft SCSI Primary Commands - 3 (SPC-3) pages 231-233
// T10/1416-D Rev 10
220
221
void  scsiPrintSelfTest(int device)
{
ballen4705's avatar
ballen4705 committed
222
	int num, k, n, res, noheader=1;
223
	UINT8 * ucp;
ballen4705's avatar
ballen4705 committed
224
	unsigned long long ull=0;
225
226
227
228
229
230
231
232
233

	if (logsense(device, SELFTEST_RESULTS_PAGE, gBuf) != 0)
	{
		perror ( "scsiPrintSelfTest Failed");
		exit (1);
	}
	if (gBuf[0] != SELFTEST_RESULTS_PAGE)
	{
		printf("Self-test Log Sense Failed\n");
ballen4705's avatar
ballen4705 committed
234
		exit(1);
235
	}
ballen4705's avatar
ballen4705 committed
236
237

	// compute page length
238
	num = (gBuf[2] << 8) + gBuf[3];
ballen4705's avatar
ballen4705 committed
239

ballen4705's avatar
ballen4705 committed
240
241
242
243
	// Log sense page length 0x190 bytes
	if (num != 0x190) {
	  printf("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num);
	  exit(1);
244
	}
ballen4705's avatar
ballen4705 committed
245
246

	// loop through the twenty possible entries
247
	for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
ballen4705's avatar
ballen4705 committed
248
249
250
251
252
	  int i;

	  // timestamp in power-on hours (or zero if test in progress)
	  n = (ucp[6] << 8) | ucp[7];

ballen4705's avatar
ballen4705 committed
253
254
	  // The spec says "all 20 bytes will be zero if no test" but
	  // DG has found otherwise.  So this is a heuristic.
ballen4705's avatar
ballen4705 committed
255
	  if ((0 == n) && (0 == ucp[4]))
256
	    break;
ballen4705's avatar
ballen4705 committed
257
258
259

	  // only print header if needed
	  if (noheader){
ballen4705's avatar
ballen4705 committed
260
	    printf("\nSMART Self-test log\n");
ballen4705's avatar
ballen4705 committed
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
	    printf("Num  Test              Status                 segment  "
		   "LifeTime  LBA_first_err [SK ASC ASQ]\n");
	    printf("     Description                              number   "
		   "(hours)\n");
	    noheader=0;
	  }

	  // print parameter code (test number) & self-test code text
	  printf("#%2d  %s", (ucp[0] << 8) | ucp[1], 
		 self_test_code[(ucp[4] >> 5) & 0x7]);

	  // self-test result
	  res = ucp[4] & 0xf;
	  printf("  %s", self_test_result[res]);

	  // self-test number identifies test that failed and consists
	  // of either the number of the segment that failed during
	  // the test, or the number of the test that failed and the
	  // number of the segment in which the test was run, using a
	  // vendor-specific method of putting both numbers into a
	  // single byte.
	  if (ucp[5])
	    printf(" %3d",  (int)ucp[5]);
	  else
ballen4705's avatar
ballen4705 committed
285
	    printf("   -");
ballen4705's avatar
ballen4705 committed
286
287
288
289

	  // print time that the self-test was completed
	  if (n==0 && res==0xf)
	    // self-test in progress
ballen4705's avatar
ballen4705 committed
290
	    printf("   NOW");
ballen4705's avatar
ballen4705 committed
291
	  else   
ballen4705's avatar
ballen4705 committed
292
	    printf(" %5d", n);
ballen4705's avatar
ballen4705 committed
293
294
295
296
297
298
299
300
301
	  
	  // construct 8-byte integer address of first failure
	  for (i=0; i<8; i++){
	    ull <<= 8;
	    ull |= ucp[i+8];
	  }

	  // print Address of First Failure, if sensible
	  if ((0xffffffffffffffffULL != ull) && (res > 0) && ( res < 0xf))
ballen4705's avatar
ballen4705 committed
302
	    printf("  0x%16llx", ull);
ballen4705's avatar
ballen4705 committed
303
	  else
ballen4705's avatar
ballen4705 committed
304
	    printf("                   -");
ballen4705's avatar
ballen4705 committed
305
306
307
308
309
310
311
312
313
314
315
316

	  // if sense key nonzero, then print it, along with
	  // additional sense code and additional sense code qualifier
	  if (ucp[16] & 0xf)
	    printf(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
	  else
	    printf(" [-   -    -]\n");
	}

	// if header never printed, then there was no output
	if (noheader)
	  printf("No self-tests have been logged\n\n");
317
	else
ballen4705's avatar
ballen4705 committed
318
319
320
	  printf("\n");

	return;
321
}
ballen4705's avatar
ballen4705 committed
322
323
324
325
326
327
 
void scsiGetDriveInfo ( int device)
{
   char manufacturer[9];
   char product[17];
   char revision[5];
328
   char timedatetz[64];
ballen4705's avatar
ballen4705 committed
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348

   UINT8 smartsupport;
	
   if (stdinquiry ( device, (UINT8 *) &gBuf) != 0)
   {
      perror ( "Standard Inquiry failed");
   }

   memset ( &manufacturer, 0, 8);
   manufacturer[8] = '\0';
   strncpy ((char *) &manufacturer, (char *) &gBuf[8], 8);
 
   memset ( &product, 0, 16);
   strncpy ((char *) &product, (char *) &gBuf[16], 16);
   product[16] = '\0';
	
   memset ( &revision, 0, 4);
   strncpy ((char *) &revision, (char *) &gBuf[32], 4);
   revision[4] = '\0';
   printf("Device: %s %s Version: %s\n", manufacturer, product, revision);
ballen4705's avatar
ballen4705 committed
349

350
351
352
   // print current time and date and timezone
   dateandtimezone(timedatetz);
   printf("Local Time is: %s\n", timedatetz);
ballen4705's avatar
ballen4705 committed
353
   
ballen4705's avatar
ballen4705 committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
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
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
   if ( scsiSmartSupport( device, (UINT8 *) &smartsupport) != 0)
   {
      printf("Device does not support %s\n",(gBuf[0] & 0x1f)?
                         "TapeAlerts": "S.M.A.R.T.");
      exit (1);
   }
	
   printf("Device supports %s and is %s\n%s\n", 
            (gBuf[0] & 0x1f)? "TapeAlerts" : "S.M.A.R.T.",
            (smartsupport & DEXCPT_ENABLE)? "Disable" : "Enabled",
            (smartsupport & EWASC_ENABLE)? "Temperature Warning Enabled":
		"Temperature Warning Disabled or Not Supported");

}


void scsiSmartEnable( int device)
{
	
	/* Enable Exception Control */

	if ( scsiSmartDEXCPTDisable(device) != 0)
	{
		exit (1);
	}
	printf("S.M.A.R.T. enabled\n");
		

	if (scsiSmartEWASCEnable(device) != 0)
	{
		printf("Temperature Warning not Supported\n");
		
	}
	else
	{
		printf("Temperature Warning Enabled\n");
		
	}

	return;

}
	

void scsiSmartDisable (int device)
{

	if ( scsiSmartDEXCPTEnable(device) != 0)
	{
		exit (1);
	}
	printf("S.M.A.R.T. Disabled\n");
		

}

void scsiPrintTemp (int device)
{
  UINT8 temp;
  UINT8 trip;

  if ( scsiGetTemp(device, &temp, &trip) != 0)
  {
   exit (1);
  }
  
  printf("Current Drive Temperature:     %d C\n", temp);
  printf("Drive Trip Temperature:        %d C\n", trip);


}

void scsiPrintStopStart ( int device )
{
/**
  unsigned int css;

  if ( scsiGetStartStop(device, unsigned int *css) != 0)
  {
   exit (1);
  }
  
  printf ("Start Stop Count: %d\n", css);
**/
}
439

440
void scsiPrintMain (char *device, int fd)
ballen4705's avatar
ballen4705 committed
441
{
442
  int checkedsupportlogpages = 0;
ballen4705's avatar
ballen4705 committed
443

444
445
446
447
448
449
  // See if unit accepts SCSI commmands from us
  if (testunitnotready(fd)){
    printf("Smartctl: device %s failed Test Unit Ready\n", device);
    exit(1);
  }

450
    if (con->driveinfo)
ballen4705's avatar
ballen4705 committed
451
452
	scsiGetDriveInfo(fd); 

453
    if (con->smartenable) 
ballen4705's avatar
ballen4705 committed
454
455
	scsiSmartEnable(fd);

456
    if (con->smartdisable)
ballen4705's avatar
ballen4705 committed
457
458
	scsiSmartDisable(fd);

459
    if (con->checksmart)
ballen4705's avatar
ballen4705 committed
460
461
    {
	scsiGetSupportPages (fd);
462
	checkedsupportlogpages = 1;
ballen4705's avatar
ballen4705 committed
463
464
465
466
467
468
469
470
471
472
473
474
        if(gTapeAlertsPage)
          scsiGetTapeAlertsData (fd);
       else
        {
           scsiGetSmartData(fd);
           if(gTempPage)
            scsiPrintTemp(fd);         
           if(gStartStopPage)
            scsiGetStartStopData (fd);
        }
    }	

475
476
477
478
479
480
    if (con->smartselftestlog) {
	if (! checkedsupportlogpages)
	    scsiGetSupportPages(fd);
	if (gSelfTestPage)
            scsiPrintSelfTest(fd);
    }
ballen4705's avatar
ballen4705 committed
481
	
482
    if ( con->smartexeoffimmediate )
ballen4705's avatar
ballen4705 committed
483
484
485
486
487
488
489
490
    {
	if ( scsiSmartOfflineTest (fd) != 0) 
	{
          printf( "Smartctl: Smart Offline Failed\n");
          exit(-1);
	}
	printf ("Drive Command Successful offline test has begun\n");

491
        printf ("Use smartctl -X to abort test\n");	
ballen4705's avatar
ballen4705 committed
492
493
494
495
			
    }


496
    if ( con->smartshortcapselftest )
ballen4705's avatar
ballen4705 committed
497
498
499
500
501
502
503
    {
	if ( scsiSmartShortCapSelfTest (fd) != 0) 
	{
            printf( "Smartctl: Smart Short Self Test Failed\n");
            exit(-1);
	}
	printf ("Drive Command Successful Short Self test has begun\n");
504
        printf ("Use smartctl -X to abort test\n");	
ballen4705's avatar
ballen4705 committed
505
506
   }

507
   if ( con->smartshortselftest )
ballen4705's avatar
ballen4705 committed
508
509
510
511
512
513
514
515
   { 
		
      if ( scsiSmartShortSelfTest (fd) != 0) 
      {
	printf( "Smartctl: Smart Short Self Test Failed\n");
	exit(-1);
      }
	printf ("Drive Command Successful Short Self test has begun\n");
516
        printf ("Use smartctl -X to abort test\n");
ballen4705's avatar
ballen4705 committed
517
518
   }
	
519
   if ( con->smartextendselftest )
ballen4705's avatar
ballen4705 committed
520
521
522
   {
      if ( scsiSmartExtendSelfTest (fd) != 0) 
      {
ballen4705's avatar
ballen4705 committed
523
	printf( "S.M.A.R.T. Extended Self Test Failed\n");
ballen4705's avatar
ballen4705 committed
524
525
526
527
	exit(-1);
      }

   printf ("Drive Command Successful Extended Self test has begun\n");
528
   printf ("Use smartctl -X to abort test\n");	
ballen4705's avatar
ballen4705 committed
529
530
   }
	
531
	if ( con->smartextendcapselftest )
ballen4705's avatar
ballen4705 committed
532
533
534
535
	{
		
		if ( scsiSmartExtendCapSelfTest (fd) != 0) 
		{
ballen4705's avatar
ballen4705 committed
536
			printf( "S.M.A.R.T. Extended Self Test Failed\n");
ballen4705's avatar
ballen4705 committed
537
538
539
540
			exit(-1);
		}
		
		printf ("Drive Command Successful Extended Self test has begun\n");
541
        printf ("Use smartctl -X to abort test\n");	
ballen4705's avatar
ballen4705 committed
542
543
	}

544
	if ( con->smartselftestabort )
ballen4705's avatar
ballen4705 committed
545
546
547
548
549
550
551
552
553
554
555
	{
		
		if ( scsiSmartSelfTestAbort (fd) != 0) 
		{
			printf( "S.M.A.R.T. Self Test Abort Failed\n");
			exit(-1);
		}
		
		printf ("Drive Command Successful self test aborted\n");
     }		
}