[Midnightbsd-cvs] src [11470] trunk/usr.bin/mt/mt.c: sync mt
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sat Jul 7 12:56:26 EDT 2018
Revision: 11470
http://svnweb.midnightbsd.org/src/?rev=11470
Author: laffer1
Date: 2018-07-07 12:56:25 -0400 (Sat, 07 Jul 2018)
Log Message:
-----------
sync mt
Modified Paths:
--------------
trunk/usr.bin/mt/Makefile
trunk/usr.bin/mt/mt.1
trunk/usr.bin/mt/mt.c
Property Changed:
----------------
trunk/usr.bin/mt/mt.1
Modified: trunk/usr.bin/mt/Makefile
===================================================================
--- trunk/usr.bin/mt/Makefile 2018-07-07 16:56:02 UTC (rev 11469)
+++ trunk/usr.bin/mt/Makefile 2018-07-07 16:56:25 UTC (rev 11470)
@@ -1,6 +1,9 @@
+# $MidnightBSD$
# @(#)Makefile 8.1 (Berkeley) 6/6/93
-# $MidnightBSD$
+# $FreeBSD: stable/10/usr.bin/mt/Makefile 280438 2015-03-24 14:36:10Z ken $
PROG= mt
+DPADD= ${LIBMT} ${LIBSBUF} ${LIBBSDXML}
+LDADD= -lmt -lsbuf -lbsdxml
.include <bsd.prog.mk>
Modified: trunk/usr.bin/mt/mt.1
===================================================================
--- trunk/usr.bin/mt/mt.1 2018-07-07 16:56:02 UTC (rev 11469)
+++ trunk/usr.bin/mt/mt.1 2018-07-07 16:56:25 UTC (rev 11470)
@@ -1,3 +1,4 @@
+.\" $MidnightBSD$
.\" Copyright (c) 1981, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -27,9 +28,9 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)mt.1 8.1 (Berkeley) 6/6/93
-.\" $MidnightBSD$
+.\" $FreeBSD: stable/10/usr.bin/mt/mt.1 325496 2017-11-06 20:08:02Z ken $
.\"
-.Dd January 20, 2008
+.Dd November 3, 2017
.Dt MT 1
.Os
.Sh NAME
@@ -71,6 +72,12 @@
Write
.Ar count
end-of-file (EOF) marks at the current position.
+This returns when the file mark has been written to the media.
+.It Cm weofi
+Write
+.Ar count
+end-of-file (EOF) marks at the current position.
+This returns as soon as the command has been validated by the tape drive.
.It Cm smk
Write
.Ar count
@@ -129,6 +136,8 @@
.It Cm offline , rewoffl
Rewind the tape and place the drive off line.
Some drives are never off line.
+.It Cm load
+Load the tape into the drive.
.It Cm retension
Re-tension the tape.
This winds the tape from the current position to the end
@@ -136,7 +145,7 @@
This sometimes improves subsequent reading and writing,
particularly for streaming drives.
Some drives do not support this.
-.It Cm status
+.It Cm ostatus
Output status information about the drive.
For SCSI magnetic tape devices,
the current operating modes of density, blocksize, and whether compression
@@ -149,6 +158,9 @@
that this information is not definitive (only BOT, End of Recorded Media, and
hardware or SCSI logical block position (if the drive supports such) are
considered definitive tape positions).
+.Pp
+Also note that this is the old status command, and will be eliminated in
+favor of the new status command (see below) in a future release.
.It Cm errstat
Output (and clear) error status information about this device.
For every normal
@@ -165,9 +177,12 @@
.It Cm eod , eom
Wind the tape to the end of the recorded data,
typically after an EOF mark where another file may be written.
+.It Cm rblim
+Report the block limits of the tape drive, including the minimum and
+maximum block size, and the block granularity if any.
.El
.Pp
-The following commands require an
+The following commands may require an
.Ar argument .
.Bl -tag -width ".Cm seteotmodel"
.It Cm sethpos
@@ -199,6 +214,183 @@
.Ar 1
or
.Ar 2 .
+.It Cm status
+Output status information about the drive.
+For SCSI magnetic tape devices,
+the current operating modes of density, blocksize, and whether compression
+is enabled is reported.
+The current state of the driver (what it thinks that
+it is doing with the device) is reported.
+.Pp
+If the driver knows the relative
+position from BOT (in terms of filemarks and records), it outputs that.
+If the tape drive supports the long form report of the
+.Tn SCSI
+READ POSITION command, the Reported File Number and Reported Record Number
+will be numbers other than -1, and there may be Flags reported as well.
+.Pp
+The BOP flag means that the logical position of the drive is at the
+beginning of the partition.
+.Pp
+The EOP flag means that the logical position of the drive is between Early
+Warning and End of Partition.
+.Pp
+The BPEW flag means that the logical position of the drive is in a
+Programmable Early Warning Zone or on the EOP side of Early Warning.
+.Pp
+Note that the Reported Record Number is the tape block or object number
+relative to the beginning of the partition.
+The Calculated Record Number is the tape block or object number relative
+to the previous file mark.
+.Pp
+Note
+that the Calculated File and Record Numbers are not definitive.
+The Reported File and Record Numbers are definitive, if they are numbers
+other than -1.
+.Bl -tag -width 6n
+.It Fl v
+Print additional status information, such as the maximum supported I/O
+size.
+.It Fl x
+Print all available status data to stdout in XML format.
+.El
+.It Cm getdensity
+Report density support information for the tape drive and any media that is
+loaded.
+Most drives will report at least basic density information similar to that
+reported by
+.Nm status
+command.
+Newer tape drives that conform to the T-10 SSC and newer tape
+specifications may report more detailed information about the types of
+tapes they support and the tape currently in the drive.
+.Bl -tag -width 6n
+.It Fl x
+Print all available density data to stdout in XML format.
+Because density information is currently included in the general status XML
+report used for
+.Nm
+status command, this will be the same XML output via
+.Do
+.Nm
+status
+.Fl x
+.Dc
+.El
+.It Cm param
+Display or set parameters.
+One of
+.Fl l ,
+.Fl s ,
+or
+.Fl x
+must be specified to indicate which operation to perform.
+See
+.Xr sa 4
+for more detailed information on the parameters.
+.Bl -tag -width 8n
+.It Fl l
+List parameters, values and descriptions.
+By default all parameters will be displayed.
+To display a specific parameter, specify the parameter with
+.Fl p .
+.It Fl p Ar name
+Specify the parameter name to list (with
+.Fl l )
+or set (with
+.Fl s ) .
+.It Fl q
+Enable quiet mode for parameter listing.
+This will suppress printing of parameter descriptions.
+.It Fl s Ar value
+Specify the parameter value to set.
+The general type of this argument (integer, unsigned integer, string) is
+determined by the type of the variable indicated by the
+.Xr sa 4
+driver.
+More detailed argument checking is done by the
+.Xr sa 4
+driver.
+.It Fl x
+Print out all parameter information in XML format.
+.El
+.It Cm protect
+Display or set drive protection parameters.
+This is used to control checking and reporting a per-block checksum for
+tape drives that support it.
+Some drives may only support some parameters.
+.Bl -tag -width 8n
+.It Fl b Ar 0|1
+Set the Recover Buffered Data Protected bit.
+If set, this indicates that checksums are transferred with the logical
+blocks transferred by the RECOVERED BUFFERED DATA
+.Tn SCSI
+command.
+.It Fl d
+Disable all protection information settings.
+.It Fl e
+Enable all protection information settings.
+The default protection method used is Reed-Solomon CRC (protection method
+1), as specified in ECMA-319.
+The default protection information length used with Reed-Solomon CRC is
+4 bytes.
+To enable all settings except one more setting, specify the
+.Fl e
+argument and then explicitly disable settings that you do not wish to
+enable.
+For example, specifying
+.Fl e
+.Fl w Ar 0
+will enable all settings except for LBP_W.
+.It Fl l
+List available protection parmeters and their current settings.
+.It Fl L Ar len
+Set the length of the protection information in bytes.
+For Reed-Solomon CRC, the protection information length should be 4 bytes.
+.It Fl m Ar num
+Specify the numeric value for the protection method.
+The numeric value for Reed-Solomon CRC is 1.
+.It Fl r Ar 0|1
+Set the LBP_R parameter.
+When set, this indicates that each block read from the tape drive will
+have a checksum at the end.
+.It Fl v
+Enable verbose mode for parameter listing.
+This will include descriptions of each parameter.
+.It Fl w Ar 0|1
+Set the LBP_W parameter.
+When set, this indicates that each block written to the tape drive will have
+a checksum at the end.
+The drive will verify the checksum before writing the block to tape.
+.El
+.It Cm locate
+Set the tape drive's logical position.
+One of
+.Fl b ,
+.Fl e ,
+.Fl f ,
+or
+.Fl s
+must be specified to indicate the type of position.
+If the partition number is specified, the drive will first relocate to the
+given partition (if it exists) and then to the position indicated within
+that partition.
+If the partition number is not specified, the drive will relocate to the
+given position within the current partition.
+.Bl -tag -width 14n
+.It Fl b Ar block_addr
+Relocate to the given tape block or logical object identifier.
+Note that the block number is the Reported Record Number that is relative
+to the beginning of the partition (or beginning of tape).
+.It Fl e
+Relocate to the end of data.
+.It Fl f Ar fileno
+Relocate to the given file number.
+.It Fl p Ar partition
+Specify the partition to change to.
+.It Fl s Ar setmark
+Relocate to the given set mark.
+.El
.It Cm comp
Set the drive's compression mode.
The non-numeric values of
@@ -234,6 +426,13 @@
display to see which compression algorithm is currently in use), the user
can manually specify one of the supported compression keywords (above), or
supply a numeric compression value from the drive's specifications.
+.Pp
+Note that for some older tape drives (for example the Exabyte 8200 and 8500
+series drives) it is necessary to switch to a different density to tell the
+drive to record data in its compressed format.
+If the user attempts to turn compression on while the uncompressed density
+is selected, the drive will return an error.
+This is generally not an issue for modern tape drives.
.It Cm density
Set the density for the drive.
For the density codes, see below.
@@ -249,13 +448,14 @@
string has been taken for.
.El
.Pp
-The following density table was taken from the
+The initial version of the density table below was taken from the
.Sq Historical sequential access density codes
table (A-1) in Revision 11 of the SCSI-3 Stream Device Commands (SSC)
working draft, dated November 11, 1997.
+Subsequent additions have come from a number of sources.
.Pp
The density codes are:
-.Bd -literal -offset 3n
+.Bd -literal -offset 2n
0x0 default for device
0xE reserved for ECMA
@@ -264,7 +464,7 @@
0x01 12.7 (0.5) 9 32 (800) NRZI R X3.22-1983 2
0x02 12.7 (0.5) 9 63 (1,600) PE R X3.39-1986 2
0x03 12.7 (0.5) 9 246 (6,250) GCR R X3.54-1986 2
-0x05 6.3 (0.25) 4/9 315 (8,000) GCR C X3.136-1986 1
+0x05 6.3 (0.25) 4/9 315 (8,000) GCR C X3.136-1986 1,3
0x06 12.7 (0.5) 9 126 (3,200) PE R X3.157-1987 2
0x07 6.3 (0.25) 4 252 (6,400) IMFM C X3.116-1986 1
0x08 3.81 (0.15) 4 315 (8,000) GCR CS X3.158-1987 1
@@ -278,8 +478,8 @@
0x11 6.3 (0.25) 26 630 (16,000) GCR C QIC-320 1,6
0x12 6.3 (0.25) 30 2,034 (51,667) RLL C QIC-1350 1,6
0x13 3.81 (0.15) 1 2,400 (61,000) DDS CS X3B5/88-185A 5
-0x14 8.0 (0.315) 1 1,703 (43,245) RLL CS X3.202-1991 5
-0x15 8.0 (0.315) 1 1,789 (45,434) RLL CS ECMA TC17 5
+0x14 8.0 (0.315) 1 1,703 (43,245) RLL CS X3.202-1991 5,11
+0x15 8.0 (0.315) 1 1,789 (45,434) RLL CS ECMA TC17 5,12
0x16 12.7 (0.5) 48 394 (10,000) MFM C X3.193-1990 1
0x17 12.7 (0.5) 48 1,673 (42,500) MFM C X3B5/91-174 1
0x18 12.7 (0.5) 112 1,673 (42,500) MFM C X3B5/92-50 1
@@ -302,11 +502,39 @@
0x29 12.7 (0.5)
0x2A
0x2B 12.7 (0.5) 3 ? ? ? C X3.267 5
+0x40 12.7 (0.5) 384 4,800 (123,952) C LTO-1
0x41 12.7 (0.5) 208 3,868 (98,250) RLL C DLTapeIV(40) 6,7
-0x48 12.7 (0.5) 448 5,236 (133,000) PRML C SDLTapeI(110) 6,8
+0x42 12.7 (0.5) 512 7,398 (187,909) C LTO-2
+0x44 12.7 (0.5) 704 9,638 (244,805) C LTO-3
+0x46 12.7 (0.5) 896 12,725 (323,215) C LTO-4
+0x47 3.81 (0.25) ? 6,417 (163,000) CS DAT-72
+0x48 12.7 (0.5) 448 5,236 (133,000) PRML C SDLTapeI(110) 6,8,13
0x49 12.7 (0.5) 448 7,598 (193,000) PRML C SDLTapeI(160) 6,8
+0x4A 12.7 (0.5) 768 ? PRML C T10000A 10
+0x4B 12.7 (0.5) 1152 ? PRML C T10000B 10
+0x4C 12.7 (0.5) 3584 ? PRML C T10000C 10
+0x4D 12.7 (0.5) 4608 ? PRML C T10000D 10
+0x51 12.7 (0.5) 512 11,800 (299,720) C 3592A1 (unencrypted)
+0x52 12.7 (0.5) 896 11,800 (299,720) C 3592A2 (unencrypted)
+0x53 12.7 (0.5) 1152 13,452 (341,681) C 3592A3 (unencrypted)
+0x54 12.7 (0.5) 2560 19,686 (500,024) C 3592A4 (unencrypted)
+0x55 12.7 (0.5) 5120 20,670 (525,018) C 3592A5 (unencrypted)
+0x56 12.7 (0.5) 7680 20,670 (525,018) C 3592B5 (unencrypted)
+0x58 12.7 (0.5) 1280 15,142 (384,607) C LTO-5
+0x5A 12.7 (0.5) 2176 15,142 (384,607) C LTO-6
+0x5C 12.7 (0.5) 3584 19,107 (485,318) C LTO-7
+0x5D 12.7 (0.5) 5376 19,107 (485,318) C LTO-M8 14
+0x5E 12.7 (0.5) 6656 20,669 (524,993) C LTO-8
+0x71 12.7 (0.5) 512 11,800 (299,720) C 3592A1 (encrypted)
+0x72 12.7 (0.5) 896 11,800 (299,720) C 3592A2 (encrypted)
+0x73 12.7 (0.5) 1152 13,452 (341,681) C 3592A3 (encrypted)
+0x74 12.7 (0.5) 2560 19,686 (500,024) C 3592A4 (encrypted)
+0x75 12.7 (0.5) 5120 20,670 (525,018) C 3592A5 (encrypted)
+0x76 12.7 (0.5) 7680 20,670 (525,018) C 3592B5 (encrypted)
+0x8c 8.0 (0.315) 1 1,789 (45,434) RLL CS EXB-8500c 5,9
+0x90 8.0 (0.315) 1 1,703 (43,245) RLL CS EXB-8200c 5,9
.Ed
-.Bd -literal -offset 3n
+.Bd -literal -offset 2n
Code Description Type Description
---- -------------------------------------- ---- -----------
NRZI Non return to zero, change on ones R Reel-to-reel
@@ -318,19 +546,86 @@
RLL Run length limited
PRML Partial Response Maximum Likelihood
.Ed
-.Bd -literal -offset 3n
+.Bd -literal -offset 2n
NOTES
-1. Serial recorded.
-2. Parallel recorded.
-3. Old format known as QIC-11.
-5. Helical scan.
-6. This is not an American National Standard. The reference is based on
- an industry standard definition of the media format.
-7. DLT recording: serially recorded track pairs (DLTapeIII and
- DLTapeIV(20)), or track quads (DLTapeIV(35) and DLTapeIV(40)).
-8. Super DLT (SDLT) recording: 56 serially recorded logical tracks with
- 8 physical tracks each.
+1. Serial recorded.
+2. Parallel recorded.
+3. Old format known as QIC-11.
+5. Helical scan.
+6. This is not an American National Standard. The reference is based
+ on an industry standard definition of the media format.
+7. DLT recording: serially recorded track pairs (DLTapeIII and
+ DLTapeIV(20)), or track quads (DLTapeIV(35) and DLTapeIV(40)).
+8. Super DLT (SDLT) recording: 56 serially recorded logical tracks
+ with 8 physical tracks each.
+9. Vendor-specific Exabyte density code for compressed format.
+10. bpi/bpmm values for the Oracle/StorageTek T10000 tape drives are
+ not listed in the manual. Someone with access to a drive can
+ supply the necessary values by running 'mt getdensity'.
+11. This is Exabyte 8200 uncompressed format. The compressed format
+ density code is 0x90.
+12. This is Exabyte 8500 uncompressed format. The compressed format
+ density code is 0x8c.
+13. This density code (0x48) was also used for DAT-160.
+14. Officially known as LTO-8 Type M, abbreviated M8. This is a pristine
+ LTO-7 cartridge initialized with a higher density format by an LTO-8
+ drive. It cannot be read by an LTO-7 drive. Uncompressed capacity
+ is 9TB, compared to 6TB for LTO-7 and 12TB for LTO-8.
.Ed
+.Bd -literal -offset 2n
+NOTE ON QIC STREAMERS
+
+The following is a table of Data Cartridge types as used in the 1/4 inch
+tape drives such as the Archive Viper 150, Wangtek 5525ES, and Tandberg
+TDC4220 tape drives:
+
+Value Reference Format Cartridge Type Capacity Tracks Length
+----- --------- ------ -------------- -------- ------ ------
+
+0x05 QIC-11 DC300 15MB 4 300ft
+0x05 QIC-11 DC300XL/P 20MB 4 450ft
+0x05 QIC-11 DC600 27MB 4 600ft
+0x05 X3.136-1986 QIC-24 DC615A 15MB 9 150ft
+0x05 X3.136-1986 QIC-24 DC300XL/P 45MB 9 450ft
+0x05 X3.136-1986 QIC-24 DC600A 60MB 9 600ft
+0x0F QIC-120 QIC-120 DC600A/DC6150 120MB 15 620ft
+0x10 QIC-150 QIC-150 DC600XTD/DC6150 150MB 18 620ft
+0x10 QIC-150 QIC-150 DC6250 250MB 18 1,020ft
+0x11 QIC-320 QIC-525 DC6320 320MB 26 620ft
+0x11 QIC-320 QIC-525 DC6525 525MB 26 1,020ft
+0x1E QIC-1000C QIC-1000 DC9100/DL9135 1.0GB 30 760ft
+0x1E QIC-1000C QIC-1000 DC9150 1.2GB 30 950ft
+0x22 QIC-2GB(C) QIC-2GB DC9200 2.0GB 42 950ft
+0x22 QIC-2GB(C) QIC-2GB DC9250 2.5GB 42 1,200ft
+.Ed
+.Pp
+Notes:
+.Pp
+QIC-24, QIC-120, QIC-150 use fixed blocksize of 512 bytes, QIC-525, QIC-1000
+and QIC-2GB can use blocksize of 1,024 bytes.
+DDS (DAT) drives generally use variable blocks.
+.Pp
+QIC-02 and QIC-36 are interface standards for tape drives.
+The QIC-02 and QIC-36 streamers such as the Wangtek 5250EQ are otherwise
+identical to their SCSI versions (i.e.: Wangtek 5250ES).
+.Pp
+It seems that the 150MB and larger streamers cannot write QIC-24 9 track
+formats, only read them.
+.Pp
+DC600A cartridges marked "10,000ftpi" can only be used as QIC-11, QIC-24,
+and QIC-120 format.
+DC600A cartridges marked 12,500ftpi can be used as both QIC-120 and QIC-150
+format.
+.Pp
+Some manufacturers do not use "DC" on their cartridges.
+Verbatim uses DL, Maxell uses MC, Sony uses QD, Quill uses DQ.
+.Pp
+3M/Imation & Fuji use DC.
+Thus a DL6250, MC-6250, QD6250, DQ6250 are all identical media to a DC6250.
+.Pp
+QIC tape media is not "connected" to the take up reels and will de-spool
+if the tape drive has dust covering the light sensor that looks for the end
+of tape holes in the media.
.Sh ENVIRONMENT
.Bl -tag -width ".Ev TAPE"
.It Ev TAPE
@@ -343,8 +638,6 @@
.El
.Sh FILES
.Bl -tag -width ".Pa /dev/*sa[0-9]*" -compact
-.It Pa /dev/*wt*
-QIC-02/QIC-36 magnetic tape interface
.It Pa /dev/*sa[0-9]*
SCSI magnetic tape interface
.El
@@ -357,7 +650,6 @@
.Sh SEE ALSO
.Xr dd 1 ,
.Xr ioctl 2 ,
-.Xr ast 4 ,
.Xr mtio 4 ,
.Xr sa 4 ,
.Xr environ 7
Property changes on: trunk/usr.bin/mt/mt.1
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.bin/mt/mt.c
===================================================================
--- trunk/usr.bin/mt/mt.c 2018-07-07 16:56:02 UTC (rev 11469)
+++ trunk/usr.bin/mt/mt.c 2018-07-07 16:56:25 UTC (rev 11470)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
@@ -26,6 +27,37 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*-
+ * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * Authors: Ken Merry (Spectra Logic Corporation)
+ */
#ifndef lint
static const char copyright[] =
@@ -40,7 +72,7 @@
#endif /* not lint */
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.bin/mt/mt.c 293290 2016-01-07 00:40:51Z bdrewery $");
/*
* mt --
@@ -49,6 +81,8 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
+#include <sys/queue.h>
+#include <sys/sbuf.h>
#include <ctype.h>
#include <err.h>
@@ -57,7 +91,17 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <bsdxml.h>
+#include <mtlib.h>
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_periph.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_sa.h>
+
/* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */
/* c_flags */
#define NEED_2ARGS 0x01
@@ -65,6 +109,7 @@
#define IS_DENSITY 0x04
#define DISABLE_THIS 0x08
#define IS_COMP 0x10
+#define USE_GETOPT 0x20
#ifndef TRUE
#define TRUE 1
@@ -72,8 +117,18 @@
#ifndef FALSE
#define FALSE 0
#endif
+#ifndef MAX
+#define MAX(a, b) (a > b) ? a : b
+#endif
+#define MT_PLURAL(a) (a == 1) ? "" : "s"
-struct commands {
+typedef enum {
+ MT_CMD_NONE = MTLOAD + 1,
+ MT_CMD_PROTECT,
+ MT_CMD_GETDENSITY
+} mt_commands;
+
+static const struct commands {
const char *c_name;
unsigned long c_code;
int c_ronly;
@@ -87,10 +142,12 @@
{ "fsf", MTFSF, 1, 0 },
{ "fsr", MTFSR, 1, 0 },
{ "offline", MTOFFL, 1, 0 },
+ { "load", MTLOAD, 1, 0 },
{ "rewind", MTREW, 1, 0 },
{ "rewoffl", MTOFFL, 1, 0 },
- { "status", MTNOP, 1, 0 },
+ { "ostatus", MTNOP, 1, 0 },
{ "weof", MTWEOF, 0, ZERO_ALLOWED },
+ { "weofi", MTWEOFI, 0, ZERO_ALLOWED },
{ "erase", MTERASE, 0, ZERO_ALLOWED},
{ "blocksize", MTSETBSIZ, 0, NEED_2ARGS|ZERO_ALLOWED },
{ "density", MTSETDNSTY, 0, NEED_2ARGS|ZERO_ALLOWED|IS_DENSITY },
@@ -111,30 +168,54 @@
{ "seteotmodel", MTIOCSETEOTMODEL, 0, NEED_2ARGS|ZERO_ALLOWED },
{ "getmodel", MTIOCGETEOTMODEL, 0, 0 },
{ "geteotmodel", MTIOCGETEOTMODEL, 0, 0 },
+ { "rblim", MTIOCRBLIM, 0, 0},
+ { "getdensity", MT_CMD_GETDENSITY, 0, USE_GETOPT},
+ { "status", MTIOCEXTGET, 0, USE_GETOPT },
+ { "locate", MTIOCEXTLOCATE, 0, USE_GETOPT },
+ { "param", MTIOCPARAMGET, 0, USE_GETOPT },
+ { "protect", MT_CMD_PROTECT, 0, USE_GETOPT },
{ NULL, 0, 0, 0 }
};
-const char *getblksiz(int);
-void printreg(const char *, u_int, const char *);
-void status(struct mtget *);
-void usage(void);
-void st_status (struct mtget *);
-int stringtodens (const char *s);
-const char *denstostring (int d);
-int denstobp(int d, int bpi);
-u_int32_t stringtocomp(const char *s);
-const char *comptostring(u_int32_t comp);
-void warn_eof(void);
+static const char *getblksiz(int);
+static void printreg(const char *, u_int, const char *);
+static void status(struct mtget *);
+static void usage(void);
+const char *get_driver_state_str(int dsreg);
+static void st_status (struct mtget *);
+static int mt_locate(int argc, char **argv, int mtfd, const char *tape);
+static int nstatus_print(int argc, char **argv, char *xml_str,
+ struct mt_status_data *status_data);
+static int mt_xml_cmd(unsigned long cmd, int argc, char **argv, int mtfd,
+ const char *tape);
+static int mt_print_density_entry(struct mt_status_entry *density_root, int indent);
+static int mt_print_density_report(struct mt_status_entry *report_root, int indent);
+static int mt_print_density(struct mt_status_entry *density_root, int indent);
+static int mt_getdensity(int argc, char **argv, char *xml_str,
+ struct mt_status_data *status_data);
+static int mt_set_param(int mtfd, struct mt_status_data *status_data,
+ char *param_name, char *param_value);
+static int mt_protect(int argc, char **argv, int mtfd,
+ struct mt_status_data *status_data);
+static int mt_param(int argc, char **argv, int mtfd, char *xml_str,
+ struct mt_status_data *status_data);
+static const char *denstostring (int d);
+static u_int32_t stringtocomp(const char *s);
+static const char *comptostring(u_int32_t comp);
+static void warn_eof(void);
+
int
main(int argc, char *argv[])
{
- struct commands *comp;
+ const struct commands *comp;
struct mtget mt_status;
struct mtop mt_com;
int ch, len, mtfd;
const char *p, *tape;
+ bzero(&mt_com, sizeof(mt_com));
+
if ((tape = getenv("TAPE")) == NULL)
tape = DEFTAPE;
@@ -145,13 +226,15 @@
tape = optarg;
break;
case '?':
+ usage();
+ break;
default:
- usage();
+ break;
}
argc -= optind;
argv += optind;
- if (argc < 1 || argc > 2)
+ if (argc < 1)
usage();
len = strlen(p = *argv++);
@@ -166,6 +249,11 @@
if(comp->c_flags & DISABLE_THIS) {
warn_eof();
}
+ if (comp->c_flags & USE_GETOPT) {
+ argc--;
+ optind = 0;
+ }
+
if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0)
err(1, "%s", tape);
if (comp->c_code != MTNOP) {
@@ -174,7 +262,7 @@
if (!isdigit(**argv) &&
(comp->c_flags & IS_DENSITY)) {
const char *dcanon;
- mt_com.mt_count = stringtodens(*argv);
+ mt_com.mt_count = mt_density_num(*argv);
if (mt_com.mt_count == 0)
errx(1, "%s: unknown density", *argv);
dcanon = denstostring(mt_com.mt_count);
@@ -191,16 +279,17 @@
errx(1, "%s: unknown compression",
*argv);
p = "";
- } else {
+ } else if ((comp->c_flags & USE_GETOPT) == 0) {
char *q;
/* allow for hex numbers; useful for density */
mt_com.mt_count = strtol(*argv, &q, 0);
p = q;
}
- if ((mt_com.mt_count <=
- ((comp->c_flags & ZERO_ALLOWED)? -1: 0)
- && ((comp->c_flags & IS_COMP) == 0)
- ) || *p)
+ if (((comp->c_flags & USE_GETOPT) == 0)
+ && (((mt_com.mt_count <=
+ ((comp->c_flags & ZERO_ALLOWED)? -1: 0))
+ && ((comp->c_flags & IS_COMP) == 0))
+ || *p))
errx(1, "%s: illegal count", *argv);
}
else
@@ -289,6 +378,47 @@
exit(0);
/* NOTREACHED */
}
+ case MTIOCRBLIM:
+ {
+ struct mtrblim rblim;
+
+ bzero(&rblim, sizeof(rblim));
+
+ if (ioctl(mtfd, MTIOCRBLIM, (caddr_t)&rblim) < 0)
+ err(2, "%s", tape);
+ (void)printf("%s:\n"
+ " min blocksize %u byte%s\n"
+ " max blocksize %u byte%s\n"
+ " granularity %u byte%s\n",
+ tape, rblim.min_block_length,
+ MT_PLURAL(rblim.min_block_length),
+ rblim.max_block_length,
+ MT_PLURAL(rblim.max_block_length),
+ (1 << rblim.granularity),
+ MT_PLURAL((1 << rblim.granularity)));
+ exit(0);
+ /* NOTREACHED */
+ }
+ case MTIOCPARAMGET:
+ case MTIOCEXTGET:
+ case MT_CMD_PROTECT:
+ case MT_CMD_GETDENSITY:
+ {
+ int retval = 0;
+
+ retval = mt_xml_cmd(comp->c_code, argc, argv, mtfd,
+ tape);
+
+ exit(retval);
+ }
+ case MTIOCEXTLOCATE:
+ {
+ int retval = 0;
+
+ retval = mt_locate(argc, argv, mtfd, tape);
+
+ exit(retval);
+ }
default:
break;
}
@@ -303,7 +433,7 @@
/* NOTREACHED */
}
-struct tape_desc {
+static const struct tape_desc {
short t_type; /* type of magtape device */
const char *t_name; /* printing name */
const char *t_dsbits; /* "drive status" register */
@@ -316,10 +446,10 @@
/*
* Interpret the status buffer returned
*/
-void
+static void
status(struct mtget *bp)
{
- struct tape_desc *mt;
+ const struct tape_desc *mt;
for (mt = tapes;; mt++) {
if (mt->t_type == 0) {
@@ -344,7 +474,7 @@
/*
* Print a register a la the %b format of the kernel's printf.
*/
-void
+static void
printreg(const char *s, u_int v, const char *bits)
{
int i, any = 0;
@@ -374,7 +504,7 @@
}
}
-void
+static void
usage(void)
{
(void)fprintf(stderr, "usage: mt [-f device] command [count]\n");
@@ -381,63 +511,7 @@
exit(1);
}
-struct densities {
- int dens;
- int bpmm;
- int bpi;
- const char *name;
-} dens[] = {
- /*
- * Taken from T10 Project 997D
- * SCSI-3 Stream Device Commands (SSC)
- * Revision 11, 4-Nov-97
- */
- /*Num. bpmm bpi Reference */
- { 0x1, 32, 800, "X3.22-1983" },
- { 0x2, 63, 1600, "X3.39-1986" },
- { 0x3, 246, 6250, "X3.54-1986" },
- { 0x5, 315, 8000, "X3.136-1986" },
- { 0x6, 126, 3200, "X3.157-1987" },
- { 0x7, 252, 6400, "X3.116-1986" },
- { 0x8, 315, 8000, "X3.158-1987" },
- { 0x9, 491, 37871, "X3.180" },
- { 0xA, 262, 6667, "X3B5/86-199" },
- { 0xB, 63, 1600, "X3.56-1986" },
- { 0xC, 500, 12690, "HI-TC1" },
- { 0xD, 999, 25380, "HI-TC2" },
- { 0xF, 394, 10000, "QIC-120" },
- { 0x10, 394, 10000, "QIC-150" },
- { 0x11, 630, 16000, "QIC-320" },
- { 0x12, 2034, 51667, "QIC-1350" },
- { 0x13, 2400, 61000, "X3B5/88-185A" },
- { 0x14, 1703, 43245, "X3.202-1991" },
- { 0x15, 1789, 45434, "ECMA TC17" },
- { 0x16, 394, 10000, "X3.193-1990" },
- { 0x17, 1673, 42500, "X3B5/91-174" },
- { 0x18, 1673, 42500, "X3B5/92-50" },
- { 0x19, 2460, 62500, "DLTapeIII" },
- { 0x1A, 3214, 81633, "DLTapeIV(20GB)" },
- { 0x1B, 3383, 85937, "DLTapeIV(35GB)" },
- { 0x1C, 1654, 42000, "QIC-385M" },
- { 0x1D, 1512, 38400, "QIC-410M" },
- { 0x1E, 1385, 36000, "QIC-1000C" },
- { 0x1F, 2666, 67733, "QIC-2100C" },
- { 0x20, 2666, 67733, "QIC-6GB(M)" },
- { 0x21, 2666, 67733, "QIC-20GB(C)" },
- { 0x22, 1600, 40640, "QIC-2GB(C)" },
- { 0x23, 2666, 67733, "QIC-875M" },
- { 0x24, 2400, 61000, "DDS-2" },
- { 0x25, 3816, 97000, "DDS-3" },
- { 0x26, 3816, 97000, "DDS-4" },
- { 0x27, 3056, 77611, "Mammoth" },
- { 0x28, 1491, 37871, "X3.224" },
- { 0x41, 3868, 98250, "DLTapeIV(40GB)" },
- { 0x48, 5236, 133000, "SDLTapeI(110)" },
- { 0x49, 7598, 193000, "SDLTapeI(160)" },
- { 0, 0, 0, NULL }
-};
-
-struct compression_types {
+static const struct compression_types {
u_int32_t comp_number;
const char *name;
} comp_types[] = {
@@ -450,63 +524,20 @@
{ 0xf0f0f0f0, NULL}
};
-const char *
+static const char *
denstostring(int d)
{
static char buf[20];
- struct densities *sd;
+ const char *name = mt_density_name(d);
- /* densities 0 and 0x7f are handled as special cases */
- if (d == 0)
- return "default";
- if (d == 0x7f)
- return "same";
- for (sd = dens; sd->dens; sd++)
- if (sd->dens == d)
- break;
- if (sd->dens == 0)
+ if (name == NULL)
sprintf(buf, "0x%02x", d);
else
- sprintf(buf, "0x%02x:%s", d, sd->name);
+ sprintf(buf, "0x%02x:%s", d, name);
return buf;
}
-/*
- * Given a specific density number, return either the bits per inch or bits
- * per millimeter for the given density.
- */
-int
-denstobp(int d, int bpi)
-{
- struct densities *sd;
-
- for (sd = dens; sd->dens; sd++)
- if (sd->dens == d)
- break;
- if (sd->dens == 0)
- return(0);
- else {
- if (bpi)
- return(sd->bpi);
- else
- return(sd->bpmm);
- }
-}
-
-int
-stringtodens(const char *s)
-{
- struct densities *sd;
- size_t l = strlen(s);
-
- for (sd = dens; sd->dens; sd++)
- if (strncasecmp(sd->name, s, l) == 0)
- break;
- return sd->dens;
-}
-
-
-const char *
+static const char *
getblksiz(int bs)
{
static char buf[25];
@@ -518,11 +549,11 @@
}
}
-const char *
+static const char *
comptostring(u_int32_t comp)
{
static char buf[20];
- struct compression_types *ct;
+ const struct compression_types *ct;
if (comp == MT_COMP_DISABLED)
return "disabled";
@@ -540,10 +571,10 @@
return(ct->name);
}
-u_int32_t
+static u_int32_t
stringtocomp(const char *s)
{
- struct compression_types *ct;
+ const struct compression_types *ct;
size_t l = strlen(s);
for (ct = comp_types; ct->name; ct++)
@@ -553,7 +584,39 @@
return(ct->comp_number);
}
-void
+static struct driver_state {
+ int dsreg;
+ const char *desc;
+} driver_states[] = {
+ { MTIO_DSREG_REST, "at rest" },
+ { MTIO_DSREG_RBSY, "Communicating with drive" },
+ { MTIO_DSREG_WR, "Writing" },
+ { MTIO_DSREG_FMK, "Writing Filemarks" },
+ { MTIO_DSREG_ZER, "Erasing" },
+ { MTIO_DSREG_RD, "Reading" },
+ { MTIO_DSREG_FWD, "Spacing Forward" },
+ { MTIO_DSREG_REV, "Spacing Reverse" },
+ { MTIO_DSREG_POS, "Hardware Positioning (direction unknown)" },
+ { MTIO_DSREG_REW, "Rewinding" },
+ { MTIO_DSREG_TEN, "Retensioning" },
+ { MTIO_DSREG_UNL, "Unloading" },
+ { MTIO_DSREG_LD, "Loading" },
+};
+
+const char *
+get_driver_state_str(int dsreg)
+{
+ unsigned int i;
+
+ for (i = 0; i < (sizeof(driver_states)/sizeof(driver_states[0])); i++) {
+ if (driver_states[i].dsreg == dsreg)
+ return (driver_states[i].desc);
+ }
+
+ return (NULL);
+}
+
+static void
st_status(struct mtget *bp)
{
printf("Mode Density Blocksize bpi "
@@ -565,76 +628,966 @@
"2: %-17s %-12s %-7d %s\n"
"3: %-17s %-12s %-7d %s\n",
denstostring(bp->mt_density), getblksiz(bp->mt_blksiz),
- denstobp(bp->mt_density, TRUE), comptostring(bp->mt_comp),
+ mt_density_bp(bp->mt_density, TRUE), comptostring(bp->mt_comp),
denstostring(bp->mt_density0), getblksiz(bp->mt_blksiz0),
- denstobp(bp->mt_density0, TRUE), comptostring(bp->mt_comp0),
+ mt_density_bp(bp->mt_density0, TRUE), comptostring(bp->mt_comp0),
denstostring(bp->mt_density1), getblksiz(bp->mt_blksiz1),
- denstobp(bp->mt_density1, TRUE), comptostring(bp->mt_comp1),
+ mt_density_bp(bp->mt_density1, TRUE), comptostring(bp->mt_comp1),
denstostring(bp->mt_density2), getblksiz(bp->mt_blksiz2),
- denstobp(bp->mt_density2, TRUE), comptostring(bp->mt_comp2),
+ mt_density_bp(bp->mt_density2, TRUE), comptostring(bp->mt_comp2),
denstostring(bp->mt_density3), getblksiz(bp->mt_blksiz3),
- denstobp(bp->mt_density3, TRUE), comptostring(bp->mt_comp3));
+ mt_density_bp(bp->mt_density3, TRUE), comptostring(bp->mt_comp3));
if (bp->mt_dsreg != MTIO_DSREG_NIL) {
- auto char foo[32];
const char sfmt[] = "Current Driver State: %s.\n";
printf("---------------------------------\n");
- switch (bp->mt_dsreg) {
- case MTIO_DSREG_REST:
- printf(sfmt, "at rest");
+ const char *state_str;
+
+ state_str = get_driver_state_str(bp->mt_dsreg);
+ if (state_str == NULL) {
+ char foo[32];
+ (void) sprintf(foo, "Unknown state 0x%x", bp->mt_dsreg);
+ printf(sfmt, foo);
+ } else {
+ printf(sfmt, state_str);
+ }
+ }
+ if (bp->mt_resid == 0 && bp->mt_fileno == (daddr_t) -1 &&
+ bp->mt_blkno == (daddr_t) -1)
+ return;
+ printf("---------------------------------\n");
+ printf("File Number: %d\tRecord Number: %d\tResidual Count %d\n",
+ bp->mt_fileno, bp->mt_blkno, bp->mt_resid);
+}
+
+static int
+mt_locate(int argc, char **argv, int mtfd, const char *tape)
+{
+ struct mtlocate mtl;
+ uint64_t logical_id = 0;
+ mt_locate_dest_type dest_type = MT_LOCATE_DEST_FILE;
+ int eod = 0, explicit = 0, immediate = 0;
+ int64_t partition = 0;
+ int block_addr_set = 0, partition_set = 0, file_set = 0, set_set = 0;
+ int c, retval;
+
+ retval = 0;
+ bzero(&mtl, sizeof(mtl));
+
+ while ((c = getopt(argc, argv, "b:eEf:ip:s:")) != -1) {
+ switch (c) {
+ case 'b':
+ /* Block address */
+ logical_id = strtoull(optarg, NULL, 0);
+ dest_type = MT_LOCATE_DEST_OBJECT;
+ block_addr_set = 1;
break;
- case MTIO_DSREG_RBSY:
- printf(sfmt, "Communicating with drive");
+ case 'e':
+ /* end of data */
+ eod = 1;
+ dest_type = MT_LOCATE_DEST_EOD;
break;
- case MTIO_DSREG_WR:
- printf(sfmt, "Writing");
+ case 'E':
+ /*
+ * XXX KDM explicit address mode. Should we even
+ * allow this, since the driver doesn't operate in
+ * explicit address mode?
+ */
+ explicit = 1;
break;
- case MTIO_DSREG_FMK:
- printf(sfmt, "Writing Filemarks");
+ case 'f':
+ /* file number */
+ logical_id = strtoull(optarg, NULL, 0);
+ dest_type = MT_LOCATE_DEST_FILE;
+ file_set = 1;
break;
- case MTIO_DSREG_ZER:
- printf(sfmt, "Erasing");
+ case 'i':
+ /*
+ * Immediate address mode. XXX KDM do we want to
+ * implement this? The other commands in the
+ * tape driver will need to be able to handle this.
+ */
+ immediate = 1;
break;
- case MTIO_DSREG_RD:
- printf(sfmt, "Reading");
+ case 'p':
+ /*
+ * Change partition to the given partition.
+ */
+ partition = strtol(optarg, NULL, 0);
+ partition_set = 1;
break;
- case MTIO_DSREG_FWD:
- printf(sfmt, "Spacing Forward");
+ case 's':
+ /* Go to the given set mark */
+ logical_id = strtoull(optarg, NULL, 0);
+ dest_type = MT_LOCATE_DEST_SET;
+ set_set = 1;
break;
- case MTIO_DSREG_REV:
- printf(sfmt, "Spacing Reverse");
+ default:
break;
- case MTIO_DSREG_POS:
- printf(sfmt,
- "Hardware Positioning (direction unknown)");
+ }
+ }
+
+ /*
+ * These options are mutually exclusive. The user may only specify
+ * one.
+ */
+ if ((block_addr_set + file_set + eod + set_set) != 1)
+ errx(1, "You must specify only one of -b, -f, -e, or -s");
+
+ mtl.dest_type = dest_type;
+ switch (dest_type) {
+ case MT_LOCATE_DEST_OBJECT:
+ case MT_LOCATE_DEST_FILE:
+ case MT_LOCATE_DEST_SET:
+ mtl.logical_id = logical_id;
+ break;
+ case MT_LOCATE_DEST_EOD:
+ break;
+ }
+
+ if (immediate != 0)
+ mtl.flags |= MT_LOCATE_FLAG_IMMED;
+
+ if (partition_set != 0) {
+ mtl.flags |= MT_LOCATE_FLAG_CHANGE_PART;
+ mtl.partition = partition;
+ }
+
+ if (explicit != 0)
+ mtl.block_address_mode = MT_LOCATE_BAM_EXPLICIT;
+ else
+ mtl.block_address_mode = MT_LOCATE_BAM_IMPLICIT;
+
+ if (ioctl(mtfd, MTIOCEXTLOCATE, &mtl) == -1)
+ err(1, "MTIOCEXTLOCATE ioctl failed on %s", tape);
+
+ return (retval);
+}
+
+typedef enum {
+ MT_PERIPH_NAME = 0,
+ MT_UNIT_NUMBER = 1,
+ MT_VENDOR = 2,
+ MT_PRODUCT = 3,
+ MT_REVISION = 4,
+ MT_COMPRESSION_SUPPORTED = 5,
+ MT_COMPRESSION_ENABLED = 6,
+ MT_COMPRESSION_ALGORITHM = 7,
+ MT_MEDIA_DENSITY = 8,
+ MT_MEDIA_BLOCKSIZE = 9,
+ MT_CALCULATED_FILENO = 10,
+ MT_CALCULATED_REL_BLKNO = 11,
+ MT_REPORTED_FILENO = 12,
+ MT_REPORTED_BLKNO = 13,
+ MT_PARTITION = 14,
+ MT_BOP = 15,
+ MT_EOP = 16,
+ MT_BPEW = 17,
+ MT_DSREG = 18,
+ MT_RESID = 19,
+ MT_FIXED_MODE = 20,
+ MT_SERIAL_NUM = 21,
+ MT_MAXIO = 22,
+ MT_CPI_MAXIO = 23,
+ MT_MAX_BLK = 24,
+ MT_MIN_BLK = 25,
+ MT_BLK_GRAN = 26,
+ MT_MAX_EFF_IOSIZE = 27
+} status_item_index;
+
+static struct mt_status_items {
+ const char *name;
+ struct mt_status_entry *entry;
+} req_status_items[] = {
+ { "periph_name", NULL },
+ { "unit_number", NULL },
+ { "vendor", NULL },
+ { "product", NULL },
+ { "revision", NULL },
+ { "compression_supported", NULL },
+ { "compression_enabled", NULL },
+ { "compression_algorithm", NULL },
+ { "media_density", NULL },
+ { "media_blocksize", NULL },
+ { "calculated_fileno", NULL },
+ { "calculated_rel_blkno", NULL },
+ { "reported_fileno", NULL },
+ { "reported_blkno", NULL },
+ { "partition", NULL },
+ { "bop", NULL },
+ { "eop", NULL },
+ { "bpew", NULL },
+ { "dsreg", NULL },
+ { "residual", NULL },
+ { "fixed_mode", NULL },
+ { "serial_num", NULL },
+ { "maxio", NULL },
+ { "cpi_maxio", NULL },
+ { "max_blk", NULL },
+ { "min_blk", NULL },
+ { "blk_gran", NULL },
+ { "max_effective_iosize", NULL }
+};
+
+int
+nstatus_print(int argc, char **argv, char *xml_str,
+ struct mt_status_data *status_data)
+{
+ unsigned int i;
+ int64_t calculated_fileno, calculated_rel_blkno;
+ int64_t rep_fileno, rep_blkno, partition, resid;
+ char block_str[32];
+ const char *dens_str;
+ int dsreg, bop, eop, bpew;
+ int xml_dump = 0;
+ size_t dens_len;
+ unsigned int field_width;
+ int verbose = 0;
+ int c;
+
+ while ((c = getopt(argc, argv, "xv")) != -1) {
+ switch (c) {
+ case 'x':
+ xml_dump = 1;
break;
- case MTIO_DSREG_REW:
- printf(sfmt, "Rewinding");
+ case 'v':
+ verbose = 1;
break;
- case MTIO_DSREG_TEN:
- printf(sfmt, "Retensioning");
+ default:
break;
- case MTIO_DSREG_UNL:
- printf(sfmt, "Unloading");
+ }
+ }
+
+ if (xml_dump != 0) {
+ printf("%s", xml_str);
+ return (0);
+ }
+
+ for (i = 0; i < (sizeof(req_status_items)/sizeof(req_status_items[0]));
+ i++) {
+ char *name;
+
+ name = __DECONST(char *, req_status_items[i].name);
+ req_status_items[i].entry = mt_status_entry_find(status_data,
+ name);
+ if (req_status_items[i].entry == NULL) {
+ errx(1, "Cannot find status entry %s",
+ req_status_items[i].name);
+ }
+ }
+
+ printf("Drive: %s%ju: <%s %s %s> Serial Number: %s\n",
+ req_status_items[MT_PERIPH_NAME].entry->value,
+ (uintmax_t)req_status_items[MT_UNIT_NUMBER].entry->value_unsigned,
+ req_status_items[MT_VENDOR].entry->value,
+ req_status_items[MT_PRODUCT].entry->value,
+ req_status_items[MT_REVISION].entry->value,
+ (req_status_items[MT_SERIAL_NUM].entry->value) ?
+ req_status_items[MT_SERIAL_NUM].entry->value : "none");
+ printf("---------------------------------\n");
+
+ /*
+ * We check to see whether we're in fixed mode or not, and don't
+ * just believe the blocksize. If the SILI bit is turned on, the
+ * blocksize will be set to 4, even though we're doing variable
+ * length (well, multiples of 4) blocks.
+ */
+ if (req_status_items[MT_FIXED_MODE].entry->value_signed == 0)
+ snprintf(block_str, sizeof(block_str), "variable");
+ else
+ snprintf(block_str, sizeof(block_str), "%s",
+ getblksiz(req_status_items[
+ MT_MEDIA_BLOCKSIZE].entry->value_unsigned));
+
+ dens_str = denstostring(req_status_items[
+ MT_MEDIA_DENSITY].entry->value_unsigned);
+ if (dens_str == NULL)
+ dens_len = 0;
+ else
+ dens_len = strlen(dens_str);
+ field_width = MAX(dens_len, 17);
+ printf("Mode %-*s Blocksize bpi Compression\n"
+ "Current: %-*s %-12s %-7d ",
+ field_width, "Density", field_width, dens_str, block_str,
+ mt_density_bp(req_status_items[
+ MT_MEDIA_DENSITY].entry->value_unsigned, TRUE));
+
+ if (req_status_items[MT_COMPRESSION_SUPPORTED].entry->value_signed == 0)
+ printf("unsupported\n");
+ else if (req_status_items[
+ MT_COMPRESSION_ENABLED].entry->value_signed == 0)
+ printf("disabled\n");
+ else {
+ printf("enabled (%s)\n",
+ comptostring(req_status_items[
+ MT_COMPRESSION_ALGORITHM].entry->value_unsigned));
+ }
+
+ dsreg = req_status_items[MT_DSREG].entry->value_signed;
+ if (dsreg != MTIO_DSREG_NIL) {
+ const char sfmt[] = "Current Driver State: %s.\n";
+ printf("---------------------------------\n");
+ const char *state_str;
+
+ state_str = get_driver_state_str(dsreg);
+ if (state_str == NULL) {
+ char foo[32];
+ (void) sprintf(foo, "Unknown state 0x%x", dsreg);
+ printf(sfmt, foo);
+ } else {
+ printf(sfmt, state_str);
+ }
+ }
+ resid = req_status_items[MT_RESID].entry->value_signed;
+ calculated_fileno = req_status_items[
+ MT_CALCULATED_FILENO].entry->value_signed;
+ calculated_rel_blkno = req_status_items[
+ MT_CALCULATED_REL_BLKNO].entry->value_signed;
+ rep_fileno = req_status_items[
+ MT_REPORTED_FILENO].entry->value_signed;
+ rep_blkno = req_status_items[
+ MT_REPORTED_BLKNO].entry->value_signed;
+ bop = req_status_items[MT_BOP].entry->value_signed;
+ eop = req_status_items[MT_EOP].entry->value_signed;
+ bpew = req_status_items[MT_BPEW].entry->value_signed;
+ partition = req_status_items[MT_PARTITION].entry->value_signed;
+
+ printf("---------------------------------\n");
+ printf("Partition: %3jd Calc File Number: %3jd "
+ " Calc Record Number: %jd\n"
+ "Residual: %3jd Reported File Number: %3jd "
+ "Reported Record Number: %jd\n", partition, calculated_fileno,
+ calculated_rel_blkno, resid, rep_fileno, rep_blkno);
+
+ printf("Flags: ");
+ if (bop > 0 || eop > 0 || bpew > 0) {
+ int need_comma = 0;
+
+ if (bop > 0) {
+ printf("BOP");
+ need_comma = 1;
+ }
+ if (eop > 0) {
+ if (need_comma != 0)
+ printf(",");
+ printf("EOP");
+ need_comma = 1;
+ }
+ if (bpew > 0) {
+ if (need_comma != 0)
+ printf(",");
+ printf("BPEW");
+ need_comma = 1;
+ }
+ } else {
+ printf("None");
+ }
+ printf("\n");
+ if (verbose != 0) {
+ printf("---------------------------------\n");
+ printf("Tape I/O parameters:\n");
+ for (i = MT_MAXIO; i <= MT_MAX_EFF_IOSIZE; i++) {
+ printf(" %s (%s): %ju bytes\n",
+ req_status_items[i].entry->desc,
+ req_status_items[i].name,
+ req_status_items[i].entry->value_unsigned);
+ }
+ }
+
+ return (0);
+}
+
+int
+mt_xml_cmd(unsigned long cmd, int argc, char **argv, int mtfd, const char *tape)
+{
+ struct mt_status_data status_data;
+#if 0
+ struct mt_status_entry *entry;
+#endif
+ char *xml_str;
+ int retval;
+ unsigned long ioctl_cmd;
+
+ switch (cmd) {
+ case MT_CMD_PROTECT:
+ case MTIOCPARAMGET:
+ ioctl_cmd = MTIOCPARAMGET;
+ break;
+ default:
+ ioctl_cmd = MTIOCEXTGET;
+ break;
+ }
+
+ retval = mt_get_xml_str(mtfd, ioctl_cmd, &xml_str);
+ if (retval != 0)
+ err(1, "Couldn't get mt XML string");
+
+ retval = mt_get_status(xml_str, &status_data);
+ if (retval != XML_STATUS_OK) {
+ warn("Couldn't get mt status for %s", tape);
+ goto bailout;
+ }
+
+ /*
+ * This gets set if there are memory allocation or other errors in
+ * our parsing of the XML.
+ */
+ if (status_data.error != 0) {
+ warnx("%s", status_data.error_str);
+ retval = 1;
+ goto bailout;
+ }
+#if 0
+ STAILQ_FOREACH(entry, &status_data.entries, links)
+ mt_status_tree_print(entry, 0, NULL);
+#endif
+
+ switch (cmd) {
+ case MTIOCEXTGET:
+ retval = nstatus_print(argc, argv, xml_str, &status_data);
+ break;
+ case MTIOCPARAMGET:
+ retval = mt_param(argc, argv, mtfd, xml_str, &status_data);
+ break;
+ case MT_CMD_PROTECT:
+ retval = mt_protect(argc, argv, mtfd, &status_data);
+ break;
+ case MT_CMD_GETDENSITY:
+ retval = mt_getdensity(argc, argv, xml_str, &status_data);
+ break;
+ }
+
+bailout:
+ if (xml_str != NULL)
+ free(xml_str);
+
+ mt_status_free(&status_data);
+
+ return (retval);
+}
+
+static int
+mt_set_param(int mtfd, struct mt_status_data *status_data, char *param_name,
+ char *param_value)
+{
+ struct mt_status_entry *entry;
+ struct mtparamset param_set;
+
+ entry = mt_status_entry_find(status_data,
+ __DECONST(char *, "mtparamget"));
+ if (entry == NULL)
+ errx(1, "Cannot find parameter root node");
+
+ bzero(¶m_set, sizeof(param_set));
+ entry = mt_entry_find(entry, param_name);
+ if (entry == NULL)
+ errx(1, "Unknown parameter name \"%s\"", param_name);
+
+ strlcpy(param_set.value_name, param_name, sizeof(param_set.value_name));
+
+ switch (entry->var_type) {
+ case MT_TYPE_INT:
+ param_set.value.value_signed = strtoll(param_value, NULL, 0);
+ param_set.value_type = MT_PARAM_SET_SIGNED;
+ param_set.value_len = entry->size;
+ break;
+ case MT_TYPE_UINT:
+ param_set.value.value_unsigned = strtoull(param_value, NULL, 0);
+ param_set.value_type = MT_PARAM_SET_UNSIGNED;
+ param_set.value_len = entry->size;
+ break;
+ case MT_TYPE_STRING: {
+ size_t param_len;
+
+ param_len = strlen(param_value) + 1;
+ if (param_len > sizeof(param_set.value.value_fixed_str)) {
+ param_set.value_type = MT_PARAM_SET_VAR_STR;
+ param_set.value.value_var_str = param_value;
+ } else {
+ param_set.value_type = MT_PARAM_SET_FIXED_STR;
+ strlcpy(param_set.value.value_fixed_str, param_value,
+ sizeof(param_set.value.value_fixed_str));
+ }
+ param_set.value_len = param_len;
+ break;
+ }
+ default:
+ errx(1, "Unknown parameter type %d for %s", entry->var_type,
+ param_name);
+ break;
+ }
+
+ if (ioctl(mtfd, MTIOCPARAMSET, ¶m_set) == -1)
+ err(1, "MTIOCPARAMSET");
+
+ if (param_set.status != MT_PARAM_STATUS_OK)
+ errx(1, "Failed to set %s: %s", param_name,
+ param_set.error_str);
+
+ return (0);
+}
+
+
+typedef enum {
+ MT_PP_LBP_R,
+ MT_PP_LBP_W,
+ MT_PP_RBDP,
+ MT_PP_PI_LENGTH,
+ MT_PP_PROT_METHOD
+} mt_protect_param;
+
+static struct mt_protect_info {
+ const char *name;
+ struct mt_status_entry *entry;
+ uint32_t value;
+} mt_protect_list[] = {
+ { "lbp_r", NULL, 0 },
+ { "lbp_w", NULL, 0 },
+ { "rbdp", NULL, 0 },
+ { "pi_length", NULL, 0 },
+ { "prot_method", NULL, 0 }
+};
+
+#define MT_NUM_PROTECT_PARAMS (sizeof(mt_protect_list)/sizeof(mt_protect_list[0]))
+
+#define MT_PROT_NAME "protection"
+
+static int
+mt_protect(int argc, char **argv, int mtfd, struct mt_status_data *status_data)
+{
+ int retval = 0;
+ int do_enable = 0, do_disable = 0, do_list = 0;
+ int rbdp_set = 0, lbp_w_set = 0, lbp_r_set = 0;
+ int prot_method_set = 0, pi_length_set = 0;
+ int verbose = 0;
+ uint32_t rbdp = 0, lbp_w = 0, lbp_r = 0;
+ uint32_t prot_method = 0, pi_length = 0;
+ struct mt_status_entry *prot_entry, *supported_entry;
+ struct mt_status_entry *entry;
+ struct mtparamset params[MT_NUM_PROTECT_PARAMS];
+ struct mtsetlist param_list;
+ unsigned int i;
+ int c;
+
+ while ((c = getopt(argc, argv, "b:delL:m:r:vw:")) != -1) {
+ switch (c) {
+ case 'b':
+ rbdp_set = 1;
+ rbdp = strtoul(optarg, NULL, 0);
+ if ((rbdp != 0) && (rbdp != 1))
+ errx(1, "valid values for -b are 0 and 1");
break;
- case MTIO_DSREG_LD:
- printf(sfmt, "Loading");
+ case 'd':
+ do_disable = 1;
break;
+ case 'e':
+ do_enable = 1;
+ break;
+ case 'l':
+ do_list = 1;
+ break;
+ case 'L':
+ pi_length_set = 1;
+ pi_length = strtoul(optarg, NULL, 0);
+ if (pi_length > SA_CTRL_DP_PI_LENGTH_MASK)
+ errx(1, "PI length %u > maximum %u",
+ pi_length, SA_CTRL_DP_PI_LENGTH_MASK);
+ break;
+ case 'm':
+ prot_method_set = 1;
+ prot_method = strtoul(optarg, NULL, 0);
+ if (prot_method > SA_CTRL_DP_METHOD_MAX)
+ errx(1, "Method %u > maximum %u",
+ prot_method, SA_CTRL_DP_METHOD_MAX);
+ break;
+ case 'r':
+ lbp_r_set = 1;
+ lbp_r = strtoul(optarg, NULL, 0);
+ if ((lbp_r != 0) && (lbp_r != 1))
+ errx(1, "valid values for -r are 0 and 1");
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'w':
+ lbp_w_set = 1;
+ lbp_w = strtoul(optarg, NULL, 0);
+ if ((lbp_w != 0) && (lbp_r != 1))
+ errx(1, "valid values for -r are 0 and 1");
+ break;
default:
- (void) sprintf(foo, "Unknown state 0x%x", bp->mt_dsreg);
- printf(sfmt, foo);
break;
}
}
- if (bp->mt_resid == 0 && bp->mt_fileno == (daddr_t) -1 &&
- bp->mt_blkno == (daddr_t) -1)
- return;
- printf("---------------------------------\n");
- printf("File Number: %d\tRecord Number: %d\tResidual Count %d\n",
- bp->mt_fileno, bp->mt_blkno, bp->mt_resid);
+
+ if ((rbdp_set + do_disable + do_enable + do_list + pi_length_set +
+ prot_method_set + lbp_r_set + lbp_w_set) == 0)
+ errx(1, "Need an argument for protect");
+
+ if ((do_disable + do_enable + do_list) != 1)
+ errx(1, "You must specify only one of -e, -d or -l");
+
+ if (do_list != 0) {
+ retval = mt_protect_print(status_data, verbose);
+ goto bailout;
+ }
+ if (do_enable != 0) {
+ /*
+ * Enable protection, but allow the user to override
+ * settings if he doesn't want everything turned on.
+ */
+ if (rbdp_set == 0)
+ rbdp = 1;
+ if (lbp_w_set == 0)
+ lbp_w = 1;
+ if (lbp_r_set == 0)
+ lbp_r = 1;
+ /*
+ * If the user doesn't override it, we default to enabling
+ * Reed-Solomon checkums.
+ */
+ if (prot_method_set == 0)
+ prot_method = SA_CTRL_DP_REED_SOLOMON;
+ if (pi_length_set == 0)
+ pi_length = SA_CTRL_DP_RS_LENGTH;
+ } else if (do_disable != 0) {
+ /*
+ * If the user wants to disable protection, we ignore any
+ * other parameters he has set. Everything gets set to 0.
+ */
+ rbdp = lbp_w = lbp_r = 0;
+ prot_method = pi_length = 0;
+ }
+
+ prot_entry = mt_status_entry_find(status_data,
+ __DECONST(char *, MT_PROT_NAME));
+ if (prot_entry == NULL)
+ errx(1, "Unable to find protection information status");
+
+ supported_entry = mt_entry_find(prot_entry,
+ __DECONST(char *, "protection_supported"));
+ if (supported_entry == NULL)
+ errx(1, "Unable to find protection support information");
+
+ if (((supported_entry->var_type == MT_TYPE_INT)
+ && (supported_entry->value_signed == 0))
+ || ((supported_entry->var_type == MT_TYPE_UINT)
+ && (supported_entry->value_unsigned == 0)))
+ errx(1, "This device does not support protection information");
+
+ mt_protect_list[MT_PP_LBP_R].value = lbp_r;
+ mt_protect_list[MT_PP_LBP_W].value = lbp_w;
+ mt_protect_list[MT_PP_RBDP].value = rbdp;
+ mt_protect_list[MT_PP_PI_LENGTH].value = pi_length;
+ mt_protect_list[MT_PP_PROT_METHOD].value = prot_method;
+
+ bzero(¶ms, sizeof(params));
+ bzero(¶m_list, sizeof(param_list));
+
+ /*
+ * Go through the list and make sure that we have this parameter,
+ * and that it is still an unsigned integer. If not, we've got a
+ * problem.
+ */
+ for (i = 0; i < MT_NUM_PROTECT_PARAMS; i++) {
+ entry = mt_entry_find(prot_entry,
+ __DECONST(char *, mt_protect_list[i].name));
+ if (entry == NULL) {
+ errx(1, "Unable to find parameter %s",
+ mt_protect_list[i].name);
+ }
+ mt_protect_list[i].entry = entry;
+
+ if (entry->var_type != MT_TYPE_UINT)
+ errx(1, "Parameter %s is type %d, not unsigned, "
+ "cannot proceed", mt_protect_list[i].name,
+ entry->var_type);
+ snprintf(params[i].value_name, sizeof(params[i].value_name),
+ "%s.%s", MT_PROT_NAME, mt_protect_list[i].name);
+ /* XXX KDM unify types here */
+ params[i].value_type = MT_PARAM_SET_UNSIGNED;
+ params[i].value_len = sizeof(mt_protect_list[i].value);
+ params[i].value.value_unsigned = mt_protect_list[i].value;
+
+ }
+ param_list.num_params = MT_NUM_PROTECT_PARAMS;
+ param_list.param_len = sizeof(params);
+ param_list.params = params;
+
+ if (ioctl(mtfd, MTIOCSETLIST, ¶m_list) == -1)
+ err(1, "error issuing MTIOCSETLIST ioctl");
+
+ for (i = 0; i < MT_NUM_PROTECT_PARAMS; i++) {
+ if (params[i].status != MT_PARAM_STATUS_OK) {
+ warnx("%s", params[i].error_str);
+ retval = 1;
+ }
+ }
+bailout:
+
+ return (retval);
}
-void
+static int
+mt_param(int argc, char **argv, int mtfd, char *xml_str,
+ struct mt_status_data *status_data)
+{
+ int list = 0, do_set = 0, xml_dump = 0;
+ char *param_name = NULL, *param_value = NULL;
+ int retval = 0, quiet = 0;
+ int c;
+
+ while ((c = getopt(argc, argv, "lp:qs:x")) != -1) {
+ switch (c) {
+ case 'l':
+ list = 1;
+ break;
+ case 'p':
+ if (param_name != NULL) {
+ warnx("Only one parameter name may be "
+ "specified");
+ retval = 1;
+ goto bailout;
+ }
+ param_name = strdup(optarg);
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 's':
+ if (param_value != NULL) {
+ warnx("Only one parameter value may be "
+ "specified");
+ retval = 1;
+ goto bailout;
+ }
+ param_value = strdup(optarg);
+ do_set = 1;
+ break;
+ case 'x':
+ xml_dump = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((list + do_set + xml_dump) != 1) {
+ warnx("You must specify only one of -s, -l or -x");
+ retval = 1;
+ goto bailout;
+ }
+
+ if (xml_dump != 0) {
+ printf("%s", xml_str);
+ retval = 0;
+ goto bailout;
+ }
+
+ if (do_set != 0) {
+ if (param_name == NULL)
+ errx(1, "You must specify -p with -s");
+
+ retval = mt_set_param(mtfd, status_data, param_name,
+ param_value);
+ } else if (list != 0)
+ retval = mt_param_list(status_data, param_name, quiet);
+
+bailout:
+ free(param_name);
+ free(param_value);
+ return (retval);
+}
+
+int
+mt_print_density_entry(struct mt_status_entry *density_root, int indent)
+{
+ struct mt_status_entry *entry;
+ int retval = 0;
+
+ STAILQ_FOREACH(entry, &density_root->child_entries, links) {
+ if (entry->var_type == MT_TYPE_NODE) {
+ retval = mt_print_density_entry(entry, indent + 2);
+ if (retval != 0)
+ break;
+ else
+ continue;
+ }
+ if ((strcmp(entry->entry_name, "primary_density_code") == 0)
+ || (strcmp(entry->entry_name, "secondary_density_code") == 0)
+ || (strcmp(entry->entry_name, "density_code") == 0)) {
+
+ printf("%*s%s (%s): %s\n", indent, "", entry->desc ?
+ entry->desc : "", entry->entry_name,
+ denstostring(entry->value_unsigned));
+ } else if (strcmp(entry->entry_name, "density_flags") == 0) {
+ printf("%*sMedium Access: ", indent, "");
+ if (entry->value_unsigned & MT_DENS_WRITE_OK) {
+ printf("Read and Write\n");
+ } else {
+ printf("Read Only\n");
+ }
+ printf("%*sDefault Density: %s\n", indent, "",
+ (entry->value_unsigned & MT_DENS_DEFLT) ? "Yes" :
+ "No");
+ printf("%*sDuplicate Density: %s\n", indent, "",
+ (entry->value_unsigned & MT_DENS_DUP) ? "Yes" :
+ "No");
+ } else if (strcmp(entry->entry_name, "media_width") == 0) {
+ printf("%*s%s (%s): %.1f mm\n", indent, "",
+ entry->desc ? entry->desc : "", entry->entry_name,
+ (double)((double)entry->value_unsigned / 10));
+ } else if (strcmp(entry->entry_name, "medium_length") == 0) {
+ printf("%*s%s (%s): %ju m\n", indent, "",
+ entry->desc ? entry->desc : "", entry->entry_name,
+ (uintmax_t)entry->value_unsigned);
+ } else if (strcmp(entry->entry_name, "capacity") == 0) {
+ printf("%*s%s (%s): %ju MB\n", indent, "", entry->desc ?
+ entry->desc : "", entry->entry_name,
+ (uintmax_t)entry->value_unsigned);
+ } else {
+ printf("%*s%s (%s): %s\n", indent, "", entry->desc ?
+ entry->desc : "", entry->entry_name, entry->value);
+ }
+ }
+
+ return (retval);
+}
+
+int
+mt_print_density_report(struct mt_status_entry *report_root, int indent)
+{
+ struct mt_status_entry *mt_report, *media_report;
+ struct mt_status_entry *entry;
+ int retval = 0;
+
+ mt_report = mt_entry_find(report_root,
+ __DECONST(char *, MT_MEDIUM_TYPE_REPORT_NAME));
+ if (mt_report == NULL)
+ return (1);
+
+ media_report = mt_entry_find(report_root,
+ __DECONST(char *, MT_MEDIA_REPORT_NAME));
+ if (media_report == NULL)
+ return (1);
+
+ if ((mt_report->value_signed == 0)
+ && (media_report->value_signed == 0)) {
+ printf("%*sThis tape drive supports the following "
+ "media densities:\n", indent, "");
+ } else if ((mt_report->value_signed == 0)
+ && (media_report->value_signed != 0)) {
+ printf("%*sThe tape currently in this drive supports "
+ "the following media densities:\n", indent, "");
+ } else if ((mt_report->value_signed != 0)
+ && (media_report->value_signed == 0)) {
+ printf("%*sThis tape drive supports the following "
+ "media types:\n", indent, "");
+ } else {
+ printf("%*sThis tape currently in this drive supports "
+ "the following media types:\n", indent, "");
+ }
+
+ STAILQ_FOREACH(entry, &report_root->child_entries, links) {
+ struct mt_status_nv *nv;
+
+ if (strcmp(entry->entry_name, MT_DENSITY_ENTRY_NAME) != 0)
+ continue;
+
+ STAILQ_FOREACH(nv, &entry->nv_list, links) {
+ if (strcmp(nv->name, "num") != 0)
+ continue;
+
+ break;
+ }
+
+ indent += 2;
+
+ printf("%*sDensity Entry", indent, "");
+ if (nv != NULL)
+ printf(" %s", nv->value);
+ printf(":\n");
+
+ retval = mt_print_density_entry(entry, indent + 2);
+
+ indent -= 2;
+ }
+
+ return (retval);
+}
+
+int
+mt_print_density(struct mt_status_entry *density_root, int indent)
+{
+ struct mt_status_entry *entry;
+ int retval = 0;
+
+ /*
+ * We should have this entry for every tape drive. This particular
+ * value is reported via the mode page block header, not the
+ * SCSI REPORT DENSITY SUPPORT command.
+ */
+ entry = mt_entry_find(density_root,
+ __DECONST(char *, MT_MEDIA_DENSITY_NAME));
+ if (entry == NULL)
+ errx(1, "Unable to find node %s", MT_MEDIA_DENSITY_NAME);
+
+ printf("%*sCurrent density: %s\n", indent, "",
+ denstostring(entry->value_unsigned));
+
+ /*
+ * It isn't an error if we don't have any density reports. Tape
+ * drives that don't support the REPORT DENSITY SUPPORT command
+ * won't have any; they will only have the current density entry
+ * above.
+ */
+ STAILQ_FOREACH(entry, &density_root->child_entries, links) {
+ if (strcmp(entry->entry_name, MT_DENSITY_REPORT_NAME) != 0)
+ continue;
+
+ retval = mt_print_density_report(entry, indent);
+ }
+
+ return (retval);
+}
+
+int
+mt_getdensity(int argc, char **argv, char *xml_str,
+ struct mt_status_data *status_data)
+{
+ int retval = 0;
+ int verbose = 0, xml_dump = 0;
+ struct mt_status_entry *density_root = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "vx")) != -1) {
+ switch (c) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ xml_dump = 1;
+ break;
+ }
+ }
+
+ if (xml_dump != 0) {
+ printf("%s", xml_str);
+ return (0);
+ }
+
+ density_root = mt_status_entry_find(status_data,
+ __DECONST(char *, MT_DENSITY_ROOT_NAME));
+ if (density_root == NULL)
+ errx(1, "Cannot find density root node %s",
+ MT_DENSITY_ROOT_NAME);
+
+ retval = mt_print_density(density_root, 0);
+
+ return (retval);
+}
+
+static void
warn_eof(void)
{
fprintf(stderr,
More information about the Midnightbsd-cvs
mailing list