Implement a new camcontrol function, 'camcontrol format'.
libcam/Makefile: Add scsi_da.c to libcam for the new scsi_format_unit() function. camcontrol.8: Update the man page for the new format functionality, and take out the examples section describing how to do it with 'camcontrol cmd'. camcontrol.c: New format functionality. Note that unlike the rest of the camcontrol subcommands, this one is interactive by default. Because of the potential destructiveness of the format command, I thought it necessary to get confirmation from the user before spamming a disk. You can disable the interactive behavior, and the status meter with command line arguments. scsi_da.c: Add the new scsi_format_unit() cdb building function and use #ifdef _KERNEL to make this file compile in both the kernel and userland. The format unit function is currently only defined in the non-kernel case, because nothing in the kernel is using it. If that changes, it should be un-ifdefed and compiled in both cases. scsi_da.h: New function declaration, CDB structure and format data structures. Thanks to Nick Hibma for providing some valuable input on these changes.
This commit is contained in:
parent
1c23847582
commit
96a93c63a8
@ -3,7 +3,7 @@
|
||||
MAINTAINER=ken@FreeBSD.ORG
|
||||
|
||||
LIB= cam
|
||||
SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_sa.c cam.c
|
||||
SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c
|
||||
INCS= camlib.h
|
||||
|
||||
MAN3= cam.3 cam_cdbparse.3
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1998, 1999 Kenneth D. Merry.
|
||||
.\" Copyright (c) 1998, 1999, 2000 Kenneth D. Merry.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
@ -128,6 +128,13 @@ negotiate
|
||||
.Op Fl W Ar bus_width
|
||||
.Op Fl v
|
||||
.Nm camcontrol
|
||||
format
|
||||
.Op device id
|
||||
.Op generic args
|
||||
.Op Fl q
|
||||
.Op Fl w
|
||||
.Op Fl y
|
||||
.Nm camcontrol
|
||||
help
|
||||
.Sh DESCRIPTION
|
||||
.Nm camcontrol
|
||||
@ -172,7 +179,7 @@ and
|
||||
.Fl u
|
||||
arguments will
|
||||
.Em not
|
||||
override a specified bus:target or bus:target:lun, howevever.
|
||||
override a specified bus:target or bus:target:lun, however.
|
||||
.Pp
|
||||
Most of the
|
||||
.Nm camcontrol
|
||||
@ -333,7 +340,7 @@ function requires the
|
||||
argument to specify the CDB. Other arguments are optional, depending on
|
||||
the command type. The command and data specification syntax is documented
|
||||
in
|
||||
.Xr cam 3 .
|
||||
.Xr cam_cdbparse 3 .
|
||||
NOTE: If the CDB specified causes data to be transfered to or from the
|
||||
SCSI device in question, you MUST specify either
|
||||
.Fl i
|
||||
@ -510,6 +517,70 @@ device until a command has been sent to the device. The
|
||||
.Fl a
|
||||
switch above will automatically send a Test Unit Ready to the device so
|
||||
negotiation parameters will take effect.
|
||||
.It format
|
||||
Issue the
|
||||
.Tn SCSI
|
||||
FORMAT UNIT command to the named device.
|
||||
.Pp
|
||||
.Em WARNING! WARNING! WARNING!
|
||||
.Pp
|
||||
Low level formatting a disk will destroy ALL data on the disk. Use
|
||||
extreme caution when issuing this command. Many users low-level format
|
||||
disks that do not really need to be low-level formatted. There are
|
||||
relatively few scenarios that call for low-level formatting a disk.
|
||||
One reason for
|
||||
low-level formatting a disk is to initialize the disk after changing
|
||||
its physical sector size. Another reason for low-level formatting a disk
|
||||
is to revive the disk if you are getting "medium format corrupted" errors
|
||||
from the disk in response to read and write requests.
|
||||
.Pp
|
||||
Some disks take longer than others to format. Users should specify a
|
||||
timeout long enough to allow the format to complete. The default format
|
||||
timeout is 3 hours, which should be long enough for most disks. Some hard
|
||||
disks will complete a format operation in a very short period of time
|
||||
(on the order of 5 minutes or less). This is often because the drive
|
||||
doesn't really support the FORMAT UNIT command -- it just accepts the
|
||||
command, waits a few minutes and then returns it.
|
||||
.Pp
|
||||
The
|
||||
.Sq format
|
||||
subcommand takes several arguments that modify its default behavior. The
|
||||
.Fl q
|
||||
and
|
||||
.Fl y
|
||||
arguments can be useful for scripts.
|
||||
.Pp
|
||||
.Bl -tag -width 123456
|
||||
.It Fl q
|
||||
Be quiet, don't print any status messages. This option will not disable
|
||||
the questions, however. To disable questions, use the
|
||||
.Fl y
|
||||
argument, below.
|
||||
.It Fl w
|
||||
Issue a non-immediate format command. By default,
|
||||
.Nm camcontrol
|
||||
issues the FORMAT UNIT command with the immediate bit set. This tells the
|
||||
device to immediately return the format command, before the format has
|
||||
actually completed. Then,
|
||||
.Nm camcontrol
|
||||
gathers
|
||||
.Tn SCSI
|
||||
sense information from the device every second to determine how far along
|
||||
in the format process it is. If the
|
||||
.Fl w
|
||||
argument is specified,
|
||||
.Nm camcontrol
|
||||
will issue a non-immediate format command, and will be unable to print any
|
||||
information to let the user know what percentage of the disk has been
|
||||
formatted.
|
||||
.It Fl y
|
||||
Don't ask any questions. By default,
|
||||
.Nm camcontrol
|
||||
will ask the user if he/she really wants to format the disk in question,
|
||||
and also if the default format command timeout is acceptable. The user
|
||||
will not be asked about the timeout if a timeout is specified on the
|
||||
command line.
|
||||
.El
|
||||
.It help
|
||||
Print out verbose usage information.
|
||||
.El
|
||||
@ -611,33 +682,6 @@ camcontrol negotiate -n da -u 3 -R 20.000 -O 15 -a
|
||||
.Pp
|
||||
Negotiate a sync rate of 20MHz and an offset of 15 with da3. Then send a
|
||||
Test Unit Ready command to make the settings take effect.
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
camcontrol cmd -n da -u 3 -v -t 7200 -c "4 0 0 0 0 0"
|
||||
.Ed
|
||||
.Pp
|
||||
Send the FORMAT UNIT (0x04) command to da3. This will low-level format the
|
||||
disk. Print sense information if the command fails, and set the timeout to
|
||||
two hours (or 7200 seconds).
|
||||
.Pp
|
||||
.Em WARNING! WARNING! WARNING!
|
||||
.Pp
|
||||
Low level formatting a disk will destroy ALL data on the disk. Use
|
||||
extreme caution when issuing this command. Many users low-level format
|
||||
disks that do not really need to be low-level formatted. There are
|
||||
relatively few scenarios that call for low-level formatting a disk.
|
||||
One reason for
|
||||
low-level formatting a disk is if you want to change the physical sector
|
||||
size of the disk. Another reason for low-level formatting a disk is to
|
||||
revive the disk if you are getting "medium format corrupted" errors from the
|
||||
disk in response to read and write requests.
|
||||
.Pp
|
||||
Some disks take longer than others to format. Users should specify a
|
||||
timeout long enough to allow the format to complete. Some hard disks
|
||||
will complete a format operation in a very short period of time (on the
|
||||
order of 5 minutes or less). This is often because the drive doesn't
|
||||
really support the FORMAT UNIT command -- it just accepts the command,
|
||||
waits a few minutes and then returns it.
|
||||
.Sh SEE ALSO
|
||||
.Xr cam 3 ,
|
||||
.Xr cam_cdbparse 3 ,
|
||||
|
@ -132,6 +132,7 @@ struct camcontrol_opts option_table[] = {
|
||||
{"negotiate", CAM_ARG_RATE, negotiate_opts},
|
||||
{"rate", CAM_ARG_RATE, negotiate_opts},
|
||||
{"debug", CAM_ARG_DEBUG, "ITSc"},
|
||||
{"format", CAM_ARG_FORMAT, "qwy"},
|
||||
{"help", CAM_ARG_USAGE, NULL},
|
||||
{"-?", CAM_ARG_USAGE, NULL},
|
||||
{"-h", CAM_ARG_USAGE, NULL},
|
||||
@ -181,6 +182,8 @@ static int get_print_cts(struct cam_device *device, int user_settings,
|
||||
int quiet, struct ccb_trans_settings *cts);
|
||||
static int ratecontrol(struct cam_device *device, int retry_count,
|
||||
int timeout, int argc, char **argv, char *combinedopt);
|
||||
static int scsiformat(struct cam_device *device, int argc, char **argv,
|
||||
char *combinedopt, int retry_count, int timeout);
|
||||
|
||||
camcontrol_optret
|
||||
getoption(char *arg, cam_argmask *argnum, char **subopt)
|
||||
@ -2652,6 +2655,311 @@ ratecontrol_bailout:
|
||||
return(retval);
|
||||
}
|
||||
|
||||
static int
|
||||
scsiformat(struct cam_device *device, int argc, char **argv,
|
||||
char *combinedopt, int retry_count, int timeout)
|
||||
{
|
||||
union ccb *ccb;
|
||||
int c;
|
||||
int ycount = 0, quiet = 0;
|
||||
int error = 0, response = 0, retval = 0;
|
||||
int use_timeout = 10800 * 1000;
|
||||
int immediate = 1;
|
||||
struct format_defect_list_header fh;
|
||||
u_int8_t *data_ptr = NULL;
|
||||
u_int32_t dxfer_len = 0;
|
||||
u_int8_t byte2 = 0;
|
||||
int num_warnings = 0;
|
||||
|
||||
ccb = cam_getccb(device);
|
||||
|
||||
if (ccb == NULL) {
|
||||
warnx("scsiformat: error allocating ccb");
|
||||
return(1);
|
||||
}
|
||||
|
||||
bzero(&(&ccb->ccb_h)[1],
|
||||
sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
|
||||
|
||||
while ((c = getopt(argc, argv, combinedopt)) != -1) {
|
||||
switch(c) {
|
||||
case 'q':
|
||||
quiet++;
|
||||
break;
|
||||
case 'w':
|
||||
immediate = 0;
|
||||
break;
|
||||
case 'y':
|
||||
ycount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (quiet == 0) {
|
||||
fprintf(stdout, "You are about to REMOVE ALL DATA from the "
|
||||
"following device:\n");
|
||||
|
||||
error = scsidoinquiry(device, argc, argv, combinedopt,
|
||||
retry_count, timeout);
|
||||
|
||||
if (error != 0) {
|
||||
warnx("scsiformat: error sending inquiry");
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
}
|
||||
|
||||
if (ycount == 0) {
|
||||
|
||||
do {
|
||||
char str[1024];
|
||||
|
||||
fprintf(stdout, "Are you SURE you want to do "
|
||||
"this? (yes/no) ");
|
||||
|
||||
if (fgets(str, sizeof(str), stdin) != NULL) {
|
||||
|
||||
if (strncasecmp(str, "yes", 3) == 0)
|
||||
response = 1;
|
||||
else if (strncasecmp(str, "no", 2) == 0)
|
||||
response = -1;
|
||||
else {
|
||||
fprintf(stdout, "Please answer"
|
||||
" \"yes\" or \"no\"\n");
|
||||
}
|
||||
}
|
||||
} while (response == 0);
|
||||
|
||||
if (response == -1) {
|
||||
error = 1;
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout != 0)
|
||||
use_timeout = timeout;
|
||||
|
||||
if (quiet == 0) {
|
||||
fprintf(stdout, "Current format timeout is %d seconds\n",
|
||||
use_timeout / 1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user hasn't disabled questions and didn't specify a
|
||||
* timeout on the command line, ask them if they want the current
|
||||
* timeout.
|
||||
*/
|
||||
if ((ycount == 0)
|
||||
&& (timeout == 0)) {
|
||||
char str[1024];
|
||||
int new_timeout = 0;
|
||||
|
||||
fprintf(stdout, "Enter new timeout in seconds or press\n"
|
||||
"return to keep the current timeout [%d] ",
|
||||
use_timeout / 1000);
|
||||
|
||||
if (fgets(str, sizeof(str), stdin) != NULL) {
|
||||
if (str[0] != '\0')
|
||||
new_timeout = atoi(str);
|
||||
}
|
||||
|
||||
if (new_timeout != 0) {
|
||||
use_timeout = new_timeout * 1000;
|
||||
fprintf(stdout, "Using new timeout value %d\n",
|
||||
use_timeout / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep this outside the if block below to silence any unused
|
||||
* variable warnings.
|
||||
*/
|
||||
bzero(&fh, sizeof(fh));
|
||||
|
||||
/*
|
||||
* If we're in immediate mode, we've got to include the format
|
||||
* header
|
||||
*/
|
||||
if (immediate != 0) {
|
||||
fh.byte2 = FU_DLH_IMMED;
|
||||
data_ptr = (u_int8_t *)&fh;
|
||||
dxfer_len = sizeof(fh);
|
||||
byte2 = FU_FMT_DATA;
|
||||
} else if (quiet == 0) {
|
||||
fprintf(stdout, "Formatting...");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
scsi_format_unit(&ccb->csio,
|
||||
/* retries */ retry_count,
|
||||
/* cbfcnp */ NULL,
|
||||
/* tag_action */ MSG_SIMPLE_Q_TAG,
|
||||
/* byte2 */ byte2,
|
||||
/* ileave */ 0,
|
||||
/* data_ptr */ data_ptr,
|
||||
/* dxfer_len */ dxfer_len,
|
||||
/* sense_len */ SSD_FULL_SIZE,
|
||||
/* timeout */ use_timeout);
|
||||
|
||||
/* Disable freezing the device queue */
|
||||
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
|
||||
|
||||
if (arglist & CAM_ARG_ERR_RECOVER)
|
||||
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
|
||||
|
||||
if (((retval = cam_send_ccb(device, ccb)) < 0)
|
||||
|| ((immediate == 0)
|
||||
&& ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
|
||||
char *errstr = "error sending format command";
|
||||
|
||||
if (retval < 0)
|
||||
warn(errstr);
|
||||
else
|
||||
warnx(errstr);
|
||||
|
||||
if (arglist & CAM_ARG_VERBOSE) {
|
||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_SCSI_STATUS_ERROR)
|
||||
scsi_sense_print(device, &ccb->csio, stderr);
|
||||
else
|
||||
fprintf(stderr, "CAM status is %#x\n",
|
||||
ccb->ccb_h.status);
|
||||
}
|
||||
error = 1;
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we ran in non-immediate mode, we already checked for errors
|
||||
* above and printed out any necessary information. If we're in
|
||||
* immediate mode, we need to loop through and get status
|
||||
* information periodically.
|
||||
*/
|
||||
if (immediate == 0) {
|
||||
if (quiet == 0) {
|
||||
fprintf(stdout, "Format Complete\n");
|
||||
}
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
|
||||
do {
|
||||
cam_status status;
|
||||
|
||||
bzero(&(&ccb->ccb_h)[1],
|
||||
sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
|
||||
|
||||
/*
|
||||
* There's really no need to do error recovery or
|
||||
* retries here, since we're just going to sit in a
|
||||
* loop and wait for the device to finish formatting.
|
||||
*/
|
||||
scsi_test_unit_ready(&ccb->csio,
|
||||
/* retries */ 0,
|
||||
/* cbfcnp */ NULL,
|
||||
/* tag_action */ MSG_SIMPLE_Q_TAG,
|
||||
/* sense_len */ SSD_FULL_SIZE,
|
||||
/* timeout */ 5000);
|
||||
|
||||
/* Disable freezing the device queue */
|
||||
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
|
||||
|
||||
retval = cam_send_ccb(device, ccb);
|
||||
|
||||
/*
|
||||
* If we get an error from the ioctl, bail out. SCSI
|
||||
* errors are expected.
|
||||
*/
|
||||
if (retval < 0) {
|
||||
warn("error sending CAMIOCOMMAND ioctl");
|
||||
if (arglist & CAM_ARG_VERBOSE) {
|
||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_SCSI_STATUS_ERROR)
|
||||
scsi_sense_print(device, &ccb->csio,
|
||||
stderr);
|
||||
else
|
||||
fprintf(stderr, "CAM status is %#x\n",
|
||||
ccb->ccb_h.status);
|
||||
}
|
||||
error = 1;
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
|
||||
status = ccb->ccb_h.status & CAM_STATUS_MASK;
|
||||
|
||||
if ((status != CAM_REQ_CMP)
|
||||
&& (status == CAM_SCSI_STATUS_ERROR)) {
|
||||
struct scsi_sense_data *sense;
|
||||
int error_code, sense_key, asc, ascq;
|
||||
|
||||
sense = &ccb->csio.sense_data;
|
||||
scsi_extract_sense(sense, &error_code, &sense_key,
|
||||
&asc, &ascq);
|
||||
|
||||
/*
|
||||
* According to the SCSI-2 and SCSI-3 specs, a
|
||||
* drive that is in the middle of a format should
|
||||
* return NOT READY with an ASC of "logical unit
|
||||
* not ready, format in progress". The sense key
|
||||
* specific bytes will then be a progress indicator.
|
||||
*/
|
||||
if ((sense_key == SSD_KEY_NOT_READY)
|
||||
&& (asc == 0x04) && (ascq == 0x04)) {
|
||||
if ((sense->extra_len >= 10)
|
||||
&& ((sense->sense_key_spec[0] &
|
||||
SSD_SCS_VALID) != 0)
|
||||
&& (quiet == 0)) {
|
||||
int val;
|
||||
u_int64_t percentage;
|
||||
|
||||
val = scsi_2btoul(
|
||||
&sense->sense_key_spec[1]);
|
||||
percentage = 10000 * val;
|
||||
|
||||
fprintf(stdout,
|
||||
"\rFormatting: %qd.%02qd %% "
|
||||
"(%d/%d) done",
|
||||
percentage / (0x10000 * 100),
|
||||
(percentage / 0x10000) % 100,
|
||||
val, 0x10000);
|
||||
fflush(stdout);
|
||||
} else if ((quiet == 0)
|
||||
&& (++num_warnings <= 1)) {
|
||||
warnx("Unexpected SCSI Sense Key "
|
||||
"Specific value returned "
|
||||
"during format:");
|
||||
scsi_sense_print(device, &ccb->csio,
|
||||
stderr);
|
||||
warnx("Unable to print status "
|
||||
"information, but format will "
|
||||
"proceed.");
|
||||
warnx("will exit when format is "
|
||||
"complete");
|
||||
}
|
||||
sleep(1);
|
||||
} else {
|
||||
warnx("Unexpected SCSI error during format");
|
||||
scsi_sense_print(device, &ccb->csio, stderr);
|
||||
error = 1;
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
|
||||
} else if (status != CAM_REQ_CMP) {
|
||||
warnx("Unexpected CAM status %#x", status);
|
||||
error = 1;
|
||||
goto scsiformat_bailout;
|
||||
}
|
||||
|
||||
} while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP);
|
||||
|
||||
if (quiet == 0)
|
||||
fprintf(stdout, "\nFormat Complete\n");
|
||||
|
||||
scsiformat_bailout:
|
||||
|
||||
cam_freeccb(ccb);
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
void
|
||||
usage(int verbose)
|
||||
{
|
||||
@ -2677,6 +2985,7 @@ usage(int verbose)
|
||||
" [-D <enable|disable>][-O offset][-q]\n"
|
||||
" [-R syncrate][-v][-T <enable|disable>]\n"
|
||||
" [-U][-W bus_width]\n"
|
||||
" camcontrol format [dev_id][generic args][-q][-w][-y]\n"
|
||||
" camcontrol help\n");
|
||||
if (!verbose)
|
||||
return;
|
||||
@ -2697,6 +3006,7 @@ usage(int verbose)
|
||||
"debug turn debugging on/off for a bus, target, or lun, or all devices\n"
|
||||
"tags report or set the number of transaction slots for a device\n"
|
||||
"negotiate report or set device negotiation parameters\n"
|
||||
"format send the SCSI FORMAT UNIT command to the named device\n"
|
||||
"help this message\n"
|
||||
"Device Identifiers:\n"
|
||||
"bus:target specify the bus and target, lun defaults to 0\n"
|
||||
@ -2745,7 +3055,11 @@ usage(int verbose)
|
||||
"-T <arg> \"enable\" or \"disable\" tagged queueing\n"
|
||||
"-U report/set user negotiation settings\n"
|
||||
"-W bus_width set the bus width in bits (8, 16 or 32)\n"
|
||||
"-v also print a Path Inquiry CCB for the controller\n",
|
||||
"-v also print a Path Inquiry CCB for the controller\n"
|
||||
"format arguments:\n"
|
||||
"-q be quiet, don't print status messages\n"
|
||||
"-w don't send immediate format command\n"
|
||||
"-y don't ask any questions\n",
|
||||
DEFAULT_DEVICE, DEFAULT_UNIT);
|
||||
}
|
||||
|
||||
@ -3005,6 +3319,10 @@ main(int argc, char **argv)
|
||||
error = ratecontrol(cam_dev, retry_count, timeout,
|
||||
argc, argv, combinedopt);
|
||||
break;
|
||||
case CAM_ARG_FORMAT:
|
||||
error = scsiformat(cam_dev, argc, argv,
|
||||
combinedopt, retry_count, timeout);
|
||||
break;
|
||||
case CAM_ARG_USAGE:
|
||||
usage(1);
|
||||
break;
|
||||
|
@ -28,12 +28,18 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include "opt_hw_wdog.h"
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bio.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include <sys/devicestat.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/disk.h>
|
||||
@ -46,6 +52,11 @@
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_extend.h>
|
||||
@ -54,6 +65,11 @@
|
||||
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <cam/scsi/scsi_da.h>
|
||||
#endif /* !_KERNEL */
|
||||
|
||||
#ifdef _KERNEL
|
||||
typedef enum {
|
||||
DA_STATE_PROBE,
|
||||
DA_STATE_NORMAL
|
||||
@ -1548,3 +1564,38 @@ dashutdown(void * arg, int howto)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
/*
|
||||
* XXX This is only left out of the kernel build to silence warnings. If,
|
||||
* for some reason this function is used in the kernel, the ifdefs should
|
||||
* be moved so it is included both in the kernel and userland.
|
||||
*/
|
||||
void
|
||||
scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int8_t byte2, u_int16_t ileave,
|
||||
u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
|
||||
u_int32_t timeout)
|
||||
{
|
||||
struct scsi_format_unit *scsi_cmd;
|
||||
|
||||
scsi_cmd = (struct scsi_format_unit *)&csio->cdb_io.cdb_bytes;
|
||||
scsi_cmd->opcode = FORMAT_UNIT;
|
||||
scsi_cmd->byte2 = byte2;
|
||||
scsi_ulto2b(ileave, scsi_cmd->interleave);
|
||||
|
||||
cam_fill_csio(csio,
|
||||
retries,
|
||||
cbfcnp,
|
||||
/*flags*/ (dxfer_len > 0) ? CAM_DIR_OUT : CAM_DIR_NONE,
|
||||
tag_action,
|
||||
data_ptr,
|
||||
dxfer_len,
|
||||
sense_len,
|
||||
sizeof(*scsi_cmd),
|
||||
timeout);
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
@ -63,6 +63,25 @@ struct scsi_rezero_unit
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: The lower three bits of byte2 of the format CDB are the same as
|
||||
* the lower three bits of byte2 of the read defect data CDB, below.
|
||||
*/
|
||||
struct scsi_format_unit
|
||||
{
|
||||
u_int8_t opcode;
|
||||
u_int8_t byte2;
|
||||
#define FU_FORMAT_MASK SRDD10_DLIST_FORMAT_MASK
|
||||
#define FU_BLOCK_FORMAT SRDD10_BLOCK_FORMAT
|
||||
#define FU_BFI_FORMAT SRDD10_BYTES_FROM_INDEX_FORMAT
|
||||
#define FU_PHYS_FORMAT SRDD10_PHYSICAL_SECTOR_FORMAT
|
||||
#define FU_CMPLST 0x08
|
||||
#define FU_FMT_DATA 0x10
|
||||
u_int8_t vendor_specific;
|
||||
u_int8_t interleave[2];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_reassign_blocks
|
||||
{
|
||||
u_int8_t opcode;
|
||||
@ -128,12 +147,40 @@ struct scsi_read_defect_data_12
|
||||
* Opcodes
|
||||
*/
|
||||
#define REZERO_UNIT 0x01
|
||||
#define FORMAT_UNIT 0x04
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define MODE_SELECT 0x15
|
||||
#define MODE_SENSE 0x1a
|
||||
#define READ_DEFECT_DATA_10 0x37
|
||||
#define READ_DEFECT_DATA_12 0xb7
|
||||
|
||||
struct format_defect_list_header
|
||||
{
|
||||
u_int8_t reserved;
|
||||
u_int8_t byte2;
|
||||
#define FU_DLH_VS 0x01
|
||||
#define FU_DLH_IMMED 0x02
|
||||
#define FU_DLH_DSP 0x04
|
||||
#define FU_DLH_IP 0x08
|
||||
#define FU_DLH_STPF 0x10
|
||||
#define FU_DLH_DCRT 0x20
|
||||
#define FU_DLH_DPRY 0x40
|
||||
#define FU_DLH_FOV 0x80
|
||||
u_int8_t defect_list_length[2];
|
||||
};
|
||||
|
||||
struct format_ipat_descriptor
|
||||
{
|
||||
u_int8_t byte1;
|
||||
#define FU_INIT_NO_HDR 0x00
|
||||
#define FU_INIT_LBA_MSB 0x40
|
||||
#define FU_INIT_LBA_EACH 0x80
|
||||
#define FU_INIT_SI 0x20
|
||||
u_int8_t pattern_type;
|
||||
#define FU_INIT_PAT_DEFAULT 0x00
|
||||
#define FU_INIT_PAT_REPEAT 0x01
|
||||
u_int8_t pat_length[2];
|
||||
};
|
||||
|
||||
struct scsi_reassign_blocks_data
|
||||
{
|
||||
@ -318,4 +365,20 @@ struct scsi_da_rw_recovery_page {
|
||||
u_int8_t recovery_time_limit[2];
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
/*
|
||||
* XXX This is only left out of the kernel build to silence warnings. If,
|
||||
* for some reason this function is used in the kernel, the ifdefs should
|
||||
* be moved so it is included both in the kernel and userland.
|
||||
*/
|
||||
#ifndef _KERNEL
|
||||
void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries,
|
||||
void (*cbfcnp)(struct cam_periph *, union ccb *),
|
||||
u_int8_t tag_action, u_int8_t byte2, u_int16_t ileave,
|
||||
u_int8_t *data_ptr, u_int32_t dxfer_len,
|
||||
u_int8_t sense_len, u_int32_t timeout);
|
||||
|
||||
#endif /* !_KERNEL */
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _SCSI_SCSI_DA_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user