Adds Host Protected Area (HPA) support for ATA disks to camcontrol
Reviewed by: mav Approved by: pjd (mentor) MFC after: 2 weeks
This commit is contained in:
parent
4c7a605968
commit
9e68761ce0
@ -27,7 +27,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd June 4, 2012
|
.Dd April 24, 2013
|
||||||
.Dt CAMCONTROL 8
|
.Dt CAMCONTROL 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -243,6 +243,18 @@
|
|||||||
.Op Fl U Ar user|master
|
.Op Fl U Ar user|master
|
||||||
.Op Fl y
|
.Op Fl y
|
||||||
.Nm
|
.Nm
|
||||||
|
.Ic hpa
|
||||||
|
.Op device id
|
||||||
|
.Op generic args
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl l
|
||||||
|
.Op Fl P
|
||||||
|
.Op Fl p Ar pwd
|
||||||
|
.Op Fl q
|
||||||
|
.Op Fl s Ar max_sectors
|
||||||
|
.Op Fl U Ar pwd
|
||||||
|
.Op Fl y
|
||||||
|
.Nm
|
||||||
.Ic help
|
.Ic help
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
@ -1205,6 +1217,73 @@ password for the specified user the command will fail.
|
|||||||
.Pp
|
.Pp
|
||||||
The password in all cases is limited to 32 characters, longer passwords will
|
The password in all cases is limited to 32 characters, longer passwords will
|
||||||
fail.
|
fail.
|
||||||
|
.It Ic hpa
|
||||||
|
Update or report Host Protected Area details.
|
||||||
|
By default
|
||||||
|
.Nm
|
||||||
|
will print out the HPA support and associated settings of the device.
|
||||||
|
The
|
||||||
|
.Ic hpa
|
||||||
|
command takes several optional arguments:
|
||||||
|
.Bl -tag -width 0n
|
||||||
|
.It Fl f
|
||||||
|
.Pp
|
||||||
|
Freeze the HPA configuration of the specified device.
|
||||||
|
.Pp
|
||||||
|
After command completion any other commands that update the HPA configuration
|
||||||
|
shall be command aborted.
|
||||||
|
Frozen mode is disabled by power-off or hardware reset.
|
||||||
|
.It Fl l
|
||||||
|
.Pp
|
||||||
|
Lock the HPA configuration of the device until a successful call to unlock or
|
||||||
|
the next power-on reset occurs.
|
||||||
|
.It Fl P
|
||||||
|
.Pp
|
||||||
|
Make the HPA max sectors persist across power-on reset or a hardware reset.
|
||||||
|
This must be used in combination with
|
||||||
|
.Fl s Ar max_sectors
|
||||||
|
.
|
||||||
|
.It Fl p Ar pwd
|
||||||
|
.Pp
|
||||||
|
Set the HPA configuration password required for unlock calls.
|
||||||
|
.It Fl q
|
||||||
|
.Pp
|
||||||
|
Be quiet, do not print any status messages.
|
||||||
|
This option will not disable the questions.
|
||||||
|
To disable questions, use the
|
||||||
|
.Fl y
|
||||||
|
argument, below.
|
||||||
|
.It Fl s Ar max_sectors
|
||||||
|
.Pp
|
||||||
|
Configures the maximum user accessible sectors of the device.
|
||||||
|
This will change the number of sectors the device reports.
|
||||||
|
.Pp
|
||||||
|
.Em WARNING! WARNING! WARNING!
|
||||||
|
.Pp
|
||||||
|
Changing the max sectors of a device using this option will make the data on
|
||||||
|
the device beyond the specified value inaccessible.
|
||||||
|
.Pp
|
||||||
|
Only one successful
|
||||||
|
.Fl s Ar max_sectors
|
||||||
|
call can be made without a power-on reset or a hardware reset of the device.
|
||||||
|
.It Fl U Ar pwd
|
||||||
|
.Pp
|
||||||
|
Unlock the HPA configuration of the specified device using the given password.
|
||||||
|
If the password specified doesn't match the password configured via
|
||||||
|
.Fl p Ar pwd
|
||||||
|
the command will fail.
|
||||||
|
.Pp
|
||||||
|
After 5 failed unlock calls, due to password miss-match, the device will refuse
|
||||||
|
additional unlock calls until after a power-on reset.
|
||||||
|
.It Fl y
|
||||||
|
.Pp
|
||||||
|
Confirm yes to dangerous options such as
|
||||||
|
.Fl e
|
||||||
|
without prompting for confirmation
|
||||||
|
.Pp
|
||||||
|
.El
|
||||||
|
The password for all HPA commands is limited to 32 characters, longer passwords
|
||||||
|
will fail.
|
||||||
.It Ic fwdownload
|
.It Ic fwdownload
|
||||||
Program firmware of the named SCSI device using the image file provided.
|
Program firmware of the named SCSI device using the image file provided.
|
||||||
.Pp
|
.Pp
|
||||||
@ -1397,6 +1476,30 @@ data from the device, so backup your data before using!
|
|||||||
.Pp
|
.Pp
|
||||||
This command can be used used against an SSD drive to restoring it to
|
This command can be used used against an SSD drive to restoring it to
|
||||||
factory default write performance.
|
factory default write performance.
|
||||||
|
.Pp
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
camcontrol hpa ada0
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Report HPA support and settings for ada0 (also reported via
|
||||||
|
identify).
|
||||||
|
.Pp
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
camcontrol hpa ada0 -s 10240
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Enables HPA on ada0 setting the maximum reported sectors to 10240.
|
||||||
|
.Pp
|
||||||
|
.Em WARNING! WARNING! WARNING!
|
||||||
|
.Pp
|
||||||
|
This will
|
||||||
|
.Em PREVENT ACCESS
|
||||||
|
to all data on the device beyond this limit until HPA is disabled by setting
|
||||||
|
HPA to native max sectors of the device, which can only be done after a
|
||||||
|
power-on or hardware reset!
|
||||||
|
.Pp
|
||||||
|
.Em DO NOT
|
||||||
|
use this on a device which has an active filesystem!
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr cam 3 ,
|
.Xr cam 3 ,
|
||||||
.Xr cam_cdbparse 3 ,
|
.Xr cam_cdbparse 3 ,
|
||||||
|
@ -45,6 +45,10 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <libutil.h>
|
#include <libutil.h>
|
||||||
|
#ifndef MINIMALISTIC
|
||||||
|
#include <limits.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cam/cam.h>
|
#include <cam/cam.h>
|
||||||
#include <cam/cam_debug.h>
|
#include <cam/cam_debug.h>
|
||||||
@ -88,7 +92,8 @@ typedef enum {
|
|||||||
CAM_CMD_SMP_PHYLIST = 0x0000001a,
|
CAM_CMD_SMP_PHYLIST = 0x0000001a,
|
||||||
CAM_CMD_SMP_MANINFO = 0x0000001b,
|
CAM_CMD_SMP_MANINFO = 0x0000001b,
|
||||||
CAM_CMD_DOWNLOAD_FW = 0x0000001c,
|
CAM_CMD_DOWNLOAD_FW = 0x0000001c,
|
||||||
CAM_CMD_SECURITY = 0x0000001d
|
CAM_CMD_SECURITY = 0x0000001d,
|
||||||
|
CAM_CMD_HPA = 0x0000001e
|
||||||
} cam_cmdmask;
|
} cam_cmdmask;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -135,6 +140,29 @@ struct camcontrol_opts {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifndef MINIMALISTIC
|
#ifndef MINIMALISTIC
|
||||||
|
struct ata_res_pass16 {
|
||||||
|
u_int16_t reserved[5];
|
||||||
|
u_int8_t flags;
|
||||||
|
u_int8_t error;
|
||||||
|
u_int8_t sector_count_exp;
|
||||||
|
u_int8_t sector_count;
|
||||||
|
u_int8_t lba_low_exp;
|
||||||
|
u_int8_t lba_low;
|
||||||
|
u_int8_t lba_mid_exp;
|
||||||
|
u_int8_t lba_mid;
|
||||||
|
u_int8_t lba_high_exp;
|
||||||
|
u_int8_t lba_high;
|
||||||
|
u_int8_t device;
|
||||||
|
u_int8_t status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ata_set_max_pwd
|
||||||
|
{
|
||||||
|
u_int16_t reserved1;
|
||||||
|
u_int8_t password[32];
|
||||||
|
u_int16_t reserved2[239];
|
||||||
|
};
|
||||||
|
|
||||||
static const char scsicmd_opts[] = "a:c:dfi:o:r";
|
static const char scsicmd_opts[] = "a:c:dfi:o:r";
|
||||||
static const char readdefect_opts[] = "f:GP";
|
static const char readdefect_opts[] = "f:GP";
|
||||||
static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
|
static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
|
||||||
@ -186,6 +214,7 @@ static struct camcontrol_opts option_table[] = {
|
|||||||
{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
|
{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
|
||||||
{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
|
{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
|
||||||
{"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"},
|
{"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"},
|
||||||
|
{"hpa", CAM_CMD_HPA, CAM_ARG_NONE, "Pflp:qs:U:y"},
|
||||||
#endif /* MINIMALISTIC */
|
#endif /* MINIMALISTIC */
|
||||||
{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
|
{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
|
||||||
{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
|
{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
|
||||||
@ -280,6 +309,8 @@ static int atapm(struct cam_device *device, int argc, char **argv,
|
|||||||
char *combinedopt, int retry_count, int timeout);
|
char *combinedopt, int retry_count, int timeout);
|
||||||
static int atasecurity(struct cam_device *device, int retry_count, int timeout,
|
static int atasecurity(struct cam_device *device, int retry_count, int timeout,
|
||||||
int argc, char **argv, char *combinedopt);
|
int argc, char **argv, char *combinedopt);
|
||||||
|
static int atahpa(struct cam_device *device, int retry_count, int timeout,
|
||||||
|
int argc, char **argv, char *combinedopt);
|
||||||
|
|
||||||
#endif /* MINIMALISTIC */
|
#endif /* MINIMALISTIC */
|
||||||
#ifndef min
|
#ifndef min
|
||||||
@ -1127,6 +1158,38 @@ camxferrate(struct cam_device *device)
|
|||||||
return(retval);
|
return(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
atahpa_print(struct ata_params *parm, u_int64_t hpasize, int header)
|
||||||
|
{
|
||||||
|
u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
|
||||||
|
((u_int32_t)parm->lba_size_2 << 16);
|
||||||
|
|
||||||
|
u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
|
||||||
|
((u_int64_t)parm->lba_size48_2 << 16) |
|
||||||
|
((u_int64_t)parm->lba_size48_3 << 32) |
|
||||||
|
((u_int64_t)parm->lba_size48_4 << 48);
|
||||||
|
|
||||||
|
if (header) {
|
||||||
|
printf("\nFeature "
|
||||||
|
"Support Enabled Value\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Host Protected Area (HPA) ");
|
||||||
|
if (parm->support.command1 & ATA_SUPPORT_PROTECTED) {
|
||||||
|
u_int64_t lba = lbasize48 ? lbasize48 : lbasize;
|
||||||
|
printf("yes %s %ju/%ju\n", (hpasize > lba) ? "yes" : "no ",
|
||||||
|
lba, hpasize);
|
||||||
|
|
||||||
|
printf("HPA - Security ");
|
||||||
|
if (parm->support.command1 & ATA_SUPPORT_MAXSECURITY)
|
||||||
|
printf("yes\n");
|
||||||
|
else
|
||||||
|
printf("no\n");
|
||||||
|
} else {
|
||||||
|
printf("no\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
atacapprint(struct ata_params *parm)
|
atacapprint(struct ata_params *parm)
|
||||||
{
|
{
|
||||||
@ -1554,6 +1617,83 @@ ata_do_28bit_cmd(struct cam_device *device, union ccb *ccb, int retries,
|
|||||||
return ata_cam_send(device, ccb, quiet);
|
return ata_cam_send(device, ccb, quiet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ata_do_cmd(struct cam_device *device, union ccb *ccb, int retries,
|
||||||
|
u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
|
||||||
|
u_int8_t tag_action, u_int8_t command, u_int8_t features,
|
||||||
|
u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
|
||||||
|
u_int16_t dxfer_len, int timeout, int force48bit)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = ata_try_pass_16(device);
|
||||||
|
if (retval == -1)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (retval == 1) {
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Try using SCSI Passthrough */
|
||||||
|
error = ata_do_pass_16(device, ccb, retries, flags, protocol,
|
||||||
|
ata_flags, tag_action, command, features,
|
||||||
|
lba, sector_count, data_ptr, dxfer_len,
|
||||||
|
timeout, 0);
|
||||||
|
|
||||||
|
if (ata_flags & AP_FLAG_CHK_COND) {
|
||||||
|
/* Decode ata_res from sense data */
|
||||||
|
struct ata_res_pass16 *res_pass16;
|
||||||
|
struct ata_res *res;
|
||||||
|
u_int i;
|
||||||
|
u_int16_t *ptr;
|
||||||
|
|
||||||
|
/* sense_data is 4 byte aligned */
|
||||||
|
ptr = (uint16_t*)(uintptr_t)&ccb->csio.sense_data;
|
||||||
|
for (i = 0; i < sizeof(*res_pass16) / 2; i++)
|
||||||
|
ptr[i] = le16toh(ptr[i]);
|
||||||
|
|
||||||
|
/* sense_data is 4 byte aligned */
|
||||||
|
res_pass16 = (struct ata_res_pass16 *)(uintptr_t)
|
||||||
|
&ccb->csio.sense_data;
|
||||||
|
res = &ccb->ataio.res;
|
||||||
|
res->flags = res_pass16->flags;
|
||||||
|
res->status = res_pass16->status;
|
||||||
|
res->error = res_pass16->error;
|
||||||
|
res->lba_low = res_pass16->lba_low;
|
||||||
|
res->lba_mid = res_pass16->lba_mid;
|
||||||
|
res->lba_high = res_pass16->lba_high;
|
||||||
|
res->device = res_pass16->device;
|
||||||
|
res->lba_low_exp = res_pass16->lba_low_exp;
|
||||||
|
res->lba_mid_exp = res_pass16->lba_mid_exp;
|
||||||
|
res->lba_high_exp = res_pass16->lba_high_exp;
|
||||||
|
res->sector_count = res_pass16->sector_count;
|
||||||
|
res->sector_count_exp = res_pass16->sector_count_exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) -
|
||||||
|
sizeof(struct ccb_hdr));
|
||||||
|
cam_fill_ataio(&ccb->ataio,
|
||||||
|
retries,
|
||||||
|
NULL,
|
||||||
|
flags,
|
||||||
|
tag_action,
|
||||||
|
data_ptr,
|
||||||
|
dxfer_len,
|
||||||
|
timeout);
|
||||||
|
|
||||||
|
if (force48bit || lba > ATA_MAX_28BIT_LBA)
|
||||||
|
ata_48bit_cmd(&ccb->ataio, command, features, lba, sector_count);
|
||||||
|
else
|
||||||
|
ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
|
||||||
|
|
||||||
|
if (ata_flags & AP_FLAG_CHK_COND)
|
||||||
|
ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
|
||||||
|
|
||||||
|
return ata_cam_send(device, ccb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_data(uint16_t *ptr, uint32_t len)
|
dump_data(uint16_t *ptr, uint32_t len)
|
||||||
{
|
{
|
||||||
@ -1570,6 +1710,278 @@ dump_data(uint16_t *ptr, uint32_t len)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_proc_resp(struct cam_device *device, union ccb *ccb,
|
||||||
|
int is48bit, u_int64_t *hpasize)
|
||||||
|
{
|
||||||
|
struct ata_res *res;
|
||||||
|
|
||||||
|
res = &ccb->ataio.res;
|
||||||
|
if (res->status & ATA_STATUS_ERROR) {
|
||||||
|
if (arglist & CAM_ARG_VERBOSE) {
|
||||||
|
cam_error_print(device, ccb, CAM_ESF_ALL,
|
||||||
|
CAM_EPF_ALL, stderr);
|
||||||
|
printf("error = 0x%02x, sector_count = 0x%04x, "
|
||||||
|
"device = 0x%02x, status = 0x%02x\n",
|
||||||
|
res->error, res->sector_count,
|
||||||
|
res->device, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res->error & ATA_ERROR_ID_NOT_FOUND) {
|
||||||
|
warnx("Max address has already been set since "
|
||||||
|
"last power-on or hardware reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arglist & CAM_ARG_VERBOSE) {
|
||||||
|
fprintf(stdout, "%s%d: Raw native max data:\n",
|
||||||
|
device->device_name, device->dev_unit_num);
|
||||||
|
/* res is 4 byte aligned */
|
||||||
|
dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res));
|
||||||
|
|
||||||
|
printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, "
|
||||||
|
"status = 0x%02x\n", res->error, res->sector_count,
|
||||||
|
res->device, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hpasize != NULL) {
|
||||||
|
if (is48bit) {
|
||||||
|
*hpasize = (((u_int64_t)((res->lba_high_exp << 16) |
|
||||||
|
(res->lba_mid_exp << 8) | res->lba_low_exp) << 24) |
|
||||||
|
((res->lba_high << 16) | (res->lba_mid << 8) |
|
||||||
|
res->lba_low)) + 1;
|
||||||
|
} else {
|
||||||
|
*hpasize = (((res->device & 0x0f) << 24) |
|
||||||
|
(res->lba_high << 16) | (res->lba_mid << 8) |
|
||||||
|
res->lba_low) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ata_read_native_max(struct cam_device *device, int retry_count,
|
||||||
|
u_int32_t timeout, union ccb *ccb,
|
||||||
|
struct ata_params *parm, u_int64_t *hpasize)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_int cmd, is48bit;
|
||||||
|
u_int8_t protocol;
|
||||||
|
|
||||||
|
is48bit = parm->support.command2 & ATA_SUPPORT_ADDRESS48;
|
||||||
|
protocol = AP_PROTO_NON_DATA;
|
||||||
|
|
||||||
|
if (is48bit) {
|
||||||
|
cmd = ATA_READ_NATIVE_MAX_ADDRESS48;
|
||||||
|
protocol |= AP_EXTEND;
|
||||||
|
} else {
|
||||||
|
cmd = ATA_READ_NATIVE_MAX_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = ata_do_cmd(device,
|
||||||
|
ccb,
|
||||||
|
retry_count,
|
||||||
|
/*flags*/CAM_DIR_IN,
|
||||||
|
/*protocol*/protocol,
|
||||||
|
/*ata_flags*/AP_FLAG_CHK_COND,
|
||||||
|
/*tag_action*/MSG_SIMPLE_Q_TAG,
|
||||||
|
/*command*/cmd,
|
||||||
|
/*features*/0,
|
||||||
|
/*lba*/0,
|
||||||
|
/*sector_count*/0,
|
||||||
|
/*data_ptr*/NULL,
|
||||||
|
/*dxfer_len*/0,
|
||||||
|
timeout ? timeout : 1000,
|
||||||
|
is48bit);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return atahpa_proc_resp(device, ccb, is48bit, hpasize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_set_max(struct cam_device *device, int retry_count,
|
||||||
|
u_int32_t timeout, union ccb *ccb,
|
||||||
|
int is48bit, u_int64_t maxsize, int persist)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_int cmd;
|
||||||
|
u_int8_t protocol;
|
||||||
|
|
||||||
|
protocol = AP_PROTO_NON_DATA;
|
||||||
|
|
||||||
|
if (is48bit) {
|
||||||
|
cmd = ATA_SET_MAX_ADDRESS48;
|
||||||
|
protocol |= AP_EXTEND;
|
||||||
|
} else {
|
||||||
|
cmd = ATA_SET_MAX_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lba's are zero indexed so the max lba is requested max - 1 */
|
||||||
|
if (maxsize)
|
||||||
|
maxsize--;
|
||||||
|
|
||||||
|
error = ata_do_cmd(device,
|
||||||
|
ccb,
|
||||||
|
retry_count,
|
||||||
|
/*flags*/CAM_DIR_OUT,
|
||||||
|
/*protocol*/protocol,
|
||||||
|
/*ata_flags*/AP_FLAG_CHK_COND,
|
||||||
|
/*tag_action*/MSG_SIMPLE_Q_TAG,
|
||||||
|
/*command*/cmd,
|
||||||
|
/*features*/ATA_HPA_FEAT_MAX_ADDR,
|
||||||
|
/*lba*/maxsize,
|
||||||
|
/*sector_count*/persist,
|
||||||
|
/*data_ptr*/NULL,
|
||||||
|
/*dxfer_len*/0,
|
||||||
|
timeout ? timeout : 1000,
|
||||||
|
is48bit);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return atahpa_proc_resp(device, ccb, is48bit, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_password(struct cam_device *device, int retry_count,
|
||||||
|
u_int32_t timeout, union ccb *ccb,
|
||||||
|
int is48bit, struct ata_set_max_pwd *pwd)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_int cmd;
|
||||||
|
u_int8_t protocol;
|
||||||
|
|
||||||
|
protocol = AP_PROTO_PIO_OUT;
|
||||||
|
cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
|
||||||
|
|
||||||
|
error = ata_do_cmd(device,
|
||||||
|
ccb,
|
||||||
|
retry_count,
|
||||||
|
/*flags*/CAM_DIR_OUT,
|
||||||
|
/*protocol*/protocol,
|
||||||
|
/*ata_flags*/AP_FLAG_CHK_COND,
|
||||||
|
/*tag_action*/MSG_SIMPLE_Q_TAG,
|
||||||
|
/*command*/cmd,
|
||||||
|
/*features*/ATA_HPA_FEAT_SET_PWD,
|
||||||
|
/*lba*/0,
|
||||||
|
/*sector_count*/0,
|
||||||
|
/*data_ptr*/(u_int8_t*)pwd,
|
||||||
|
/*dxfer_len*/sizeof(struct ata_set_max_pwd),
|
||||||
|
timeout ? timeout : 1000,
|
||||||
|
is48bit);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return atahpa_proc_resp(device, ccb, is48bit, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_lock(struct cam_device *device, int retry_count,
|
||||||
|
u_int32_t timeout, union ccb *ccb, int is48bit)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_int cmd;
|
||||||
|
u_int8_t protocol;
|
||||||
|
|
||||||
|
protocol = AP_PROTO_NON_DATA;
|
||||||
|
cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
|
||||||
|
|
||||||
|
error = ata_do_cmd(device,
|
||||||
|
ccb,
|
||||||
|
retry_count,
|
||||||
|
/*flags*/CAM_DIR_OUT,
|
||||||
|
/*protocol*/protocol,
|
||||||
|
/*ata_flags*/AP_FLAG_CHK_COND,
|
||||||
|
/*tag_action*/MSG_SIMPLE_Q_TAG,
|
||||||
|
/*command*/cmd,
|
||||||
|
/*features*/ATA_HPA_FEAT_LOCK,
|
||||||
|
/*lba*/0,
|
||||||
|
/*sector_count*/0,
|
||||||
|
/*data_ptr*/NULL,
|
||||||
|
/*dxfer_len*/0,
|
||||||
|
timeout ? timeout : 1000,
|
||||||
|
is48bit);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return atahpa_proc_resp(device, ccb, is48bit, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_unlock(struct cam_device *device, int retry_count,
|
||||||
|
u_int32_t timeout, union ccb *ccb,
|
||||||
|
int is48bit, struct ata_set_max_pwd *pwd)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_int cmd;
|
||||||
|
u_int8_t protocol;
|
||||||
|
|
||||||
|
protocol = AP_PROTO_PIO_OUT;
|
||||||
|
cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
|
||||||
|
|
||||||
|
error = ata_do_cmd(device,
|
||||||
|
ccb,
|
||||||
|
retry_count,
|
||||||
|
/*flags*/CAM_DIR_OUT,
|
||||||
|
/*protocol*/protocol,
|
||||||
|
/*ata_flags*/AP_FLAG_CHK_COND,
|
||||||
|
/*tag_action*/MSG_SIMPLE_Q_TAG,
|
||||||
|
/*command*/cmd,
|
||||||
|
/*features*/ATA_HPA_FEAT_UNLOCK,
|
||||||
|
/*lba*/0,
|
||||||
|
/*sector_count*/0,
|
||||||
|
/*data_ptr*/(u_int8_t*)pwd,
|
||||||
|
/*dxfer_len*/sizeof(struct ata_set_max_pwd),
|
||||||
|
timeout ? timeout : 1000,
|
||||||
|
is48bit);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return atahpa_proc_resp(device, ccb, is48bit, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_freeze_lock(struct cam_device *device, int retry_count,
|
||||||
|
u_int32_t timeout, union ccb *ccb, int is48bit)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_int cmd;
|
||||||
|
u_int8_t protocol;
|
||||||
|
|
||||||
|
protocol = AP_PROTO_NON_DATA;
|
||||||
|
cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
|
||||||
|
|
||||||
|
error = ata_do_cmd(device,
|
||||||
|
ccb,
|
||||||
|
retry_count,
|
||||||
|
/*flags*/CAM_DIR_OUT,
|
||||||
|
/*protocol*/protocol,
|
||||||
|
/*ata_flags*/AP_FLAG_CHK_COND,
|
||||||
|
/*tag_action*/MSG_SIMPLE_Q_TAG,
|
||||||
|
/*command*/cmd,
|
||||||
|
/*features*/ATA_HPA_FEAT_FREEZE,
|
||||||
|
/*lba*/0,
|
||||||
|
/*sector_count*/0,
|
||||||
|
/*data_ptr*/NULL,
|
||||||
|
/*dxfer_len*/0,
|
||||||
|
timeout ? timeout : 1000,
|
||||||
|
is48bit);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
return atahpa_proc_resp(device, ccb, is48bit, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ata_do_identify(struct cam_device *device, int retry_count, int timeout,
|
ata_do_identify(struct cam_device *device, int retry_count, int timeout,
|
||||||
union ccb *ccb, struct ata_params** ident_bufp)
|
union ccb *ccb, struct ata_params** ident_bufp)
|
||||||
@ -1701,6 +2113,7 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
|
|||||||
{
|
{
|
||||||
union ccb *ccb;
|
union ccb *ccb;
|
||||||
struct ata_params *ident_buf;
|
struct ata_params *ident_buf;
|
||||||
|
u_int64_t hpasize;
|
||||||
|
|
||||||
if ((ccb = cam_getccb(device)) == NULL) {
|
if ((ccb = cam_getccb(device)) == NULL) {
|
||||||
warnx("couldn't allocate CCB");
|
warnx("couldn't allocate CCB");
|
||||||
@ -1712,10 +2125,21 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) {
|
||||||
|
if (ata_read_native_max(device, retry_count, timeout, ccb,
|
||||||
|
ident_buf, &hpasize) != 0) {
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hpasize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
printf("%s%d: ", device->device_name, device->dev_unit_num);
|
printf("%s%d: ", device->device_name, device->dev_unit_num);
|
||||||
ata_print_ident(ident_buf);
|
ata_print_ident(ident_buf);
|
||||||
camxferrate(device);
|
camxferrate(device);
|
||||||
atacapprint(ident_buf);
|
atacapprint(ident_buf);
|
||||||
|
atahpa_print(ident_buf, hpasize, 0);
|
||||||
|
|
||||||
free(ident_buf);
|
free(ident_buf);
|
||||||
cam_freeccb(ccb);
|
cam_freeccb(ccb);
|
||||||
@ -2044,6 +2468,245 @@ ata_getpwd(u_int8_t *passwd, int max, char opt)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ATA_HPA_ACTION_PRINT,
|
||||||
|
ATA_HPA_ACTION_SET_MAX,
|
||||||
|
ATA_HPA_ACTION_SET_PWD,
|
||||||
|
ATA_HPA_ACTION_LOCK,
|
||||||
|
ATA_HPA_ACTION_UNLOCK,
|
||||||
|
ATA_HPA_ACTION_FREEZE_LOCK
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa_set_confirm(struct cam_device *device, struct ata_params* ident_buf,
|
||||||
|
u_int64_t maxsize, int persist)
|
||||||
|
{
|
||||||
|
printf("\nYou are about to configure HPA to limit the user accessible\n"
|
||||||
|
"sectors to %ju %s on the device:\n%s%d,%s%d: ", maxsize,
|
||||||
|
persist ? "persistently" : "temporarily",
|
||||||
|
device->device_name, device->dev_unit_num,
|
||||||
|
device->given_dev_name, device->given_unit_number);
|
||||||
|
ata_print_ident(ident_buf);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
char str[50];
|
||||||
|
printf("\nAre you SURE you want to configure HPA? (yes/no) ");
|
||||||
|
|
||||||
|
if (NULL != fgets(str, sizeof(str), stdin)) {
|
||||||
|
if (0 == strncasecmp(str, "yes", 3)) {
|
||||||
|
return (1);
|
||||||
|
} else if (0 == strncasecmp(str, "no", 2)) {
|
||||||
|
return (0);
|
||||||
|
} else {
|
||||||
|
printf("Please answer \"yes\" or "
|
||||||
|
"\"no\"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTREACHED */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atahpa(struct cam_device *device, int retry_count, int timeout,
|
||||||
|
int argc, char **argv, char *combinedopt)
|
||||||
|
{
|
||||||
|
union ccb *ccb;
|
||||||
|
struct ata_params *ident_buf;
|
||||||
|
struct ccb_getdev cgd;
|
||||||
|
struct ata_set_max_pwd pwd;
|
||||||
|
int error, confirm, quiet, c, action, actions, setpwd, persist;
|
||||||
|
int security, is48bit, pwdsize;
|
||||||
|
u_int64_t hpasize, maxsize;
|
||||||
|
|
||||||
|
actions = 0;
|
||||||
|
setpwd = 0;
|
||||||
|
confirm = 0;
|
||||||
|
quiet = 0;
|
||||||
|
maxsize = 0;
|
||||||
|
persist = 0;
|
||||||
|
security = 0;
|
||||||
|
|
||||||
|
memset(&pwd, 0, sizeof(pwd));
|
||||||
|
|
||||||
|
/* default action is to print hpa information */
|
||||||
|
action = ATA_HPA_ACTION_PRINT;
|
||||||
|
pwdsize = sizeof(pwd.password);
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, combinedopt)) != -1) {
|
||||||
|
switch(c){
|
||||||
|
case 's':
|
||||||
|
action = ATA_HPA_ACTION_SET_MAX;
|
||||||
|
maxsize = strtoumax(optarg, NULL, 0);
|
||||||
|
actions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (ata_getpwd(pwd.password, pwdsize, c) != 0)
|
||||||
|
return (1);
|
||||||
|
action = ATA_HPA_ACTION_SET_PWD;
|
||||||
|
security = 1;
|
||||||
|
actions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
action = ATA_HPA_ACTION_LOCK;
|
||||||
|
security = 1;
|
||||||
|
actions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
if (ata_getpwd(pwd.password, pwdsize, c) != 0)
|
||||||
|
return (1);
|
||||||
|
action = ATA_HPA_ACTION_UNLOCK;
|
||||||
|
security = 1;
|
||||||
|
actions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
action = ATA_HPA_ACTION_FREEZE_LOCK;
|
||||||
|
security = 1;
|
||||||
|
actions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
persist = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'y':
|
||||||
|
confirm++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'q':
|
||||||
|
quiet++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions > 1) {
|
||||||
|
warnx("too many hpa actions specified");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_cgd(device, &cgd) != 0) {
|
||||||
|
warnx("couldn't get CGD");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ccb = cam_getccb(device);
|
||||||
|
if (ccb == NULL) {
|
||||||
|
warnx("couldn't allocate CCB");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
|
||||||
|
if (error != 0) {
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quiet == 0) {
|
||||||
|
printf("%s%d: ", device->device_name, device->dev_unit_num);
|
||||||
|
ata_print_ident(ident_buf);
|
||||||
|
camxferrate(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == ATA_HPA_ACTION_PRINT) {
|
||||||
|
error = ata_read_native_max(device, retry_count, timeout, ccb,
|
||||||
|
ident_buf, &hpasize);
|
||||||
|
if (error == 0)
|
||||||
|
atahpa_print(ident_buf, hpasize, 1);
|
||||||
|
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
free(ident_buf);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ident_buf->support.command1 & ATA_SUPPORT_PROTECTED)) {
|
||||||
|
warnx("HPA is not supported by this device");
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
free(ident_buf);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (security && !(ident_buf->support.command1 & ATA_SUPPORT_MAXSECURITY)) {
|
||||||
|
warnx("HPA Security is not supported by this device");
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
free(ident_buf);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
is48bit = ident_buf->support.command2 & ATA_SUPPORT_ADDRESS48;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ATA spec requires:
|
||||||
|
* 1. Read native max addr is called directly before set max addr
|
||||||
|
* 2. Read native max addr is NOT called before any other set max call
|
||||||
|
*/
|
||||||
|
switch(action) {
|
||||||
|
case ATA_HPA_ACTION_SET_MAX:
|
||||||
|
if (confirm == 0 &&
|
||||||
|
atahpa_set_confirm(device, ident_buf, maxsize,
|
||||||
|
persist) == 0) {
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
free(ident_buf);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = ata_read_native_max(device, retry_count, timeout,
|
||||||
|
ccb, ident_buf, &hpasize);
|
||||||
|
if (error == 0) {
|
||||||
|
error = atahpa_set_max(device, retry_count, timeout,
|
||||||
|
ccb, is48bit, maxsize, persist);
|
||||||
|
if (error == 0) {
|
||||||
|
/* redo identify to get new lba values */
|
||||||
|
error = ata_do_identify(device, retry_count,
|
||||||
|
timeout, ccb,
|
||||||
|
&ident_buf);
|
||||||
|
atahpa_print(ident_buf, hpasize, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ATA_HPA_ACTION_SET_PWD:
|
||||||
|
error = atahpa_password(device, retry_count, timeout,
|
||||||
|
ccb, is48bit, &pwd);
|
||||||
|
if (error == 0)
|
||||||
|
printf("HPA password has been set\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ATA_HPA_ACTION_LOCK:
|
||||||
|
error = atahpa_lock(device, retry_count, timeout,
|
||||||
|
ccb, is48bit);
|
||||||
|
if (error == 0)
|
||||||
|
printf("HPA has been locked\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ATA_HPA_ACTION_UNLOCK:
|
||||||
|
error = atahpa_unlock(device, retry_count, timeout,
|
||||||
|
ccb, is48bit, &pwd);
|
||||||
|
if (error == 0)
|
||||||
|
printf("HPA has been unlocked\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ATA_HPA_ACTION_FREEZE_LOCK:
|
||||||
|
error = atahpa_freeze_lock(device, retry_count, timeout,
|
||||||
|
ccb, is48bit);
|
||||||
|
if (error == 0)
|
||||||
|
printf("HPA has been frozen\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errx(1, "Option currently not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
free(ident_buf);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
atasecurity(struct cam_device *device, int retry_count, int timeout,
|
atasecurity(struct cam_device *device, int retry_count, int timeout,
|
||||||
int argc, char **argv, char *combinedopt)
|
int argc, char **argv, char *combinedopt)
|
||||||
@ -6702,6 +7365,8 @@ usage(int printlong)
|
|||||||
" <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
|
" <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
|
||||||
" [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n"
|
" [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n"
|
||||||
" [-U <user|master>] [-y]\n"
|
" [-U <user|master>] [-y]\n"
|
||||||
|
" camcontrol hpa [dev_id][generic args] [-f] [-l] [-P] [-p pwd]\n"
|
||||||
|
" [-q] [-s max_sectors] [-U pwd] [-y]\n"
|
||||||
#endif /* MINIMALISTIC */
|
#endif /* MINIMALISTIC */
|
||||||
" camcontrol help\n");
|
" camcontrol help\n");
|
||||||
if (!printlong)
|
if (!printlong)
|
||||||
@ -6852,6 +7517,17 @@ usage(int printlong)
|
|||||||
"-T timeout overrides the timeout (seconds) used for erase operation\n"
|
"-T timeout overrides the timeout (seconds) used for erase operation\n"
|
||||||
"-U <user|master> specifies which user to set: user or master\n"
|
"-U <user|master> specifies which user to set: user or master\n"
|
||||||
"-y don't ask any questions\n"
|
"-y don't ask any questions\n"
|
||||||
|
"hpa arguments:\n"
|
||||||
|
"-f freeze the HPA configuration of the device\n"
|
||||||
|
"-l lock the HPA configuration of the device\n"
|
||||||
|
"-P make the HPA max sectors persist\n"
|
||||||
|
"-p pwd Set the HPA configuration password required for unlock\n"
|
||||||
|
" calls\n"
|
||||||
|
"-q be quiet, do not print any status messages\n"
|
||||||
|
"-s sectors configures the maximum user accessible sectors of the\n"
|
||||||
|
" device\n"
|
||||||
|
"-U pwd unlock the HPA configuration of the device\n"
|
||||||
|
"-y don't ask any questions\n"
|
||||||
);
|
);
|
||||||
#endif /* MINIMALISTIC */
|
#endif /* MINIMALISTIC */
|
||||||
}
|
}
|
||||||
@ -7076,6 +7752,10 @@ main(int argc, char **argv)
|
|||||||
case CAM_CMD_DEVLIST:
|
case CAM_CMD_DEVLIST:
|
||||||
error = getdevlist(cam_dev);
|
error = getdevlist(cam_dev);
|
||||||
break;
|
break;
|
||||||
|
case CAM_CMD_HPA:
|
||||||
|
error = atahpa(cam_dev, retry_count, timeout,
|
||||||
|
argc, argv, combinedopt);
|
||||||
|
break;
|
||||||
#endif /* MINIMALISTIC */
|
#endif /* MINIMALISTIC */
|
||||||
case CAM_CMD_DEVTREE:
|
case CAM_CMD_DEVTREE:
|
||||||
error = getdevtree();
|
error = getdevtree();
|
||||||
|
@ -283,6 +283,23 @@ struct ata_params {
|
|||||||
#define ATA_DEV_SLAVE 0x10
|
#define ATA_DEV_SLAVE 0x10
|
||||||
#define ATA_DEV_LBA 0x40
|
#define ATA_DEV_LBA 0x40
|
||||||
|
|
||||||
|
/* ATA limits */
|
||||||
|
#define ATA_MAX_28BIT_LBA 268435455UL
|
||||||
|
|
||||||
|
/* ATA Status Register */
|
||||||
|
#define ATA_STATUS_ERROR 0x01
|
||||||
|
#define ATA_STATUS_DEVICE_FAULT 0x20
|
||||||
|
|
||||||
|
/* ATA Error Register */
|
||||||
|
#define ATA_ERROR_ABORT 0x04
|
||||||
|
#define ATA_ERROR_ID_NOT_FOUND 0x10
|
||||||
|
|
||||||
|
/* ATA HPA Features */
|
||||||
|
#define ATA_HPA_FEAT_MAX_ADDR 0x00
|
||||||
|
#define ATA_HPA_FEAT_SET_PWD 0x01
|
||||||
|
#define ATA_HPA_FEAT_LOCK 0x02
|
||||||
|
#define ATA_HPA_FEAT_UNLOCK 0x03
|
||||||
|
#define ATA_HPA_FEAT_FREEZE 0x04
|
||||||
|
|
||||||
/* ATA transfer modes */
|
/* ATA transfer modes */
|
||||||
#define ATA_MODE_MASK 0x0f
|
#define ATA_MODE_MASK 0x0f
|
||||||
|
Loading…
Reference in New Issue
Block a user