Page MenuHomeFreeBSD

D29018.id84996.diff
No OneTemporary

D29018.id84996.diff

Index: sbin/camcontrol/Makefile
===================================================================
--- sbin/camcontrol/Makefile
+++ sbin/camcontrol/Makefile
@@ -5,7 +5,7 @@
PACKAGE=runtime
PROG= camcontrol
SRCS= camcontrol.c util.c
-SRCS+= attrib.c epc.c fwdownload.c modeedit.c persist.c progress.c timestamp.c zone.c
+SRCS+= attrib.c depop.c epc.c fwdownload.c modeedit.c persist.c progress.c timestamp.c zone.c
.if ${MK_NVME} != "no"
.PATH: ${SRCTOP}/sbin/nvmecontrol
CFLAGS+= -I${SRCTOP}/sbin/nvmecontrol -DWITH_NVME
Index: sbin/camcontrol/camcontrol.h
===================================================================
--- sbin/camcontrol/camcontrol.h
+++ sbin/camcontrol/camcontrol.h
@@ -88,6 +88,9 @@
int timestamp(struct cam_device *device, int argc, char **argv,
char *combinedopt, int task_attr, int retry_count, int timeout,
int verbosemode);
+int depop(struct cam_device *device, int argc, char **argv,
+ char *combinedopt, int task_attr, int retry_count, int timeout,
+ int verbosemode);
void mode_sense(struct cam_device *device, int *cdb_len, int dbd, int llbaa,
int pc, int page, int subpage, int task_attr, int retry_count,
int timeout, uint8_t *data, int datalen);
Index: sbin/camcontrol/camcontrol.8
===================================================================
--- sbin/camcontrol/camcontrol.8
+++ sbin/camcontrol/camcontrol.8
@@ -366,6 +366,13 @@
.Ic devtype
.Op device id
.Nm
+.Ic depop
+.Op device id
+.Op generic args
+.Ao Fl l | Fl d | Fl r Ac
+.Op Fl e Ar elem
+.Op Fl c Ar capacity
+.Nm
.Ic help
.Sh DESCRIPTION
The
@@ -2594,6 +2601,50 @@
.It illegal
A programming error occurred
.El
+.It Ic depop
+Commands necessary to support the depopulation (depop) of defective elements of a device
+(usually heads).
+Issues either GET PHYSICAL ELEMENT STATUS, REMOVE ELEMENT AND TRUNCATE, RESTORE
+ELEMENT AND REBUILD, or TEST UNIT READY commands to manage storage elements of a
+drive.
+Removal or restoration of elements may take hours to complete.
+One of the
+.Fl d ,
+.Fl l ,
+or
+.Fl r
+options must be specified.
+These options are mutually exclusive.
+Only SCSI drives are supported.
+Changing the storage elements of a storage drive may result in the loss of all
+data on that storage drive.
+.Bl -tag -width 6n
+.Fl c Ar capacity
+Specify the desired capacity point for the drive.
+Valid only for the
+.Fl d
+flag.
+.If Fl d
+Remove the physical element from service or set the capacity point specified by the
+.Fl e
+or
+.Fl c
+flags.
+The drive's capacity may be reduced by this operation.
+The drive may need to reinitialize after this command.
+The data on the drive is inaccessible until any such reinitialization completes.
+.Fl e Ar element
+Specify the physical element to remove from service.
+Valid only for the
+.Fl d
+flag.
+.If Fl l
+Report the current status of the physical elements of a drive.
+.If Fl r
+Restore all the eligible physical elements to service.
+The drive may need to reinitialize after this command.
+The data on the drive is inaccessible until any such reinitialization completes.
+.El
.It Ic help
Print out verbose usage information.
.El
Index: sbin/camcontrol/camcontrol.c
===================================================================
--- sbin/camcontrol/camcontrol.c
+++ sbin/camcontrol/camcontrol.c
@@ -111,6 +111,7 @@
CAM_CMD_POWER_MODE,
CAM_CMD_DEVTYPE,
CAM_CMD_AMA,
+ CAM_CMD_DEPOP,
} cam_cmd;
typedef enum {
@@ -228,6 +229,7 @@
{"zone", CAM_CMD_ZONE, CAM_ARG_NONE, "ac:l:No:P:"},
{"epc", CAM_CMD_EPC, CAM_ARG_NONE, "c:dDeHp:Pr:sS:T:"},
{"timestamp", CAM_CMD_TIMESTAMP, CAM_ARG_NONE, "f:mrsUT:"},
+ {"depop", CAM_CMD_DEPOP, CAM_ARG_NONE, "ac:de:ls"},
{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
{"-h", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
@@ -9946,6 +9948,7 @@
" camcontrol timestamp [dev_id][generic_args] <-r [-f format|-m|-U]>|\n"
" <-s <-f format -T time | -U >>\n"
" camcontrol devtype [dev_id]\n"
+" camcontrol depop [dev_id]\n"
" camcontrol mmcsdcmd [dev_id] [[-c mmc_opcode] [-a mmc_arg]\n"
" [-f mmc_flags] [-l data_len]\n"
" [-W [-b data_byte]]] |\n"
@@ -9999,6 +10002,7 @@
"epc send ATA Extended Power Conditions commands\n"
"timestamp report or set the device's timestamp\n"
"devtype report the type of device\n"
+"depop manage drive storage elements\n"
"mmcsdcmd send the given MMC command, needs -c and -a as well\n"
"help this message\n"
"Device Identifiers:\n"
@@ -10208,6 +10212,11 @@
"-f format the format of the time string passed into strptime(3)\n"
"-T time the time value passed into strptime(3)\n"
"-U set the timestamp of the device to UTC time\n"
+"depop arguments:\n"
+"-a elm restore element elm to service\n"
+"-d elm remove element elm from service\n"
+"-l list status of all elements of drive\n"
+"-s report status of pending depop operation\n"
"mmcsdcmd arguments:\n"
"-c mmc_cmd MMC command to send to the card\n"
"-a mmc_arg Argument for the MMC command\n"
@@ -10631,6 +10640,11 @@
task_attr, retry_count, timeout,
arglist & CAM_ARG_VERBOSE);
break;
+ case CAM_CMD_DEPOP:
+ error = depop(cam_dev, argc, argv, combinedopt,
+ task_attr, retry_count, timeout,
+ arglist & CAM_ARG_VERBOSE);
+ break;
case CAM_CMD_USAGE:
usage(1);
break;
Index: sbin/camcontrol/depop.c
===================================================================
--- /dev/null
+++ sbin/camcontrol/depop.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright (c) 2021 Netflix, Inc.
+ *
+ * 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.
+ *
+ */
+/*
+ * SCSI disk depop (head depopulation) support
+ *
+ * The standard defines 'storage elements' as the generic way of referring to a
+ * disk drive head. Each storage element has an identifier and an active status.
+ * The health of an element can be querried. Active elements may be removed from
+ * service with a REMOVE ELEMENT AND TRUNCATE (RET) command. Inactive element
+ * may be returned to service with a RESTORE ELEMENTS AND REBUILD (RER)
+ * command. GET PHYSICAL ELEMENT STATUS (GPES) will return a list of elements,
+ * their health, whether they are in service, how much capacity the element is
+ * used for, etc.
+ *
+ * While a depop operation is underway, the drive's format is unstable. No I/O
+ * can be done to the drive and a limited number of CDBs will succeed. Status
+ * can be obtained by either a TEST UNIT READY or a GPES command. A drive reset
+ * will not stop a depop operation, but a power cycle will. A failed depop
+ * operation will be reported when the next TEST UNIT READY is sent to the
+ * drive.
+ *
+ * 'depop' provides a wrapper around all these functions.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+#include <camlib.h>
+#include <scsi_wrap.h>
+#include "camcontrol.h"
+
+enum depop_action {
+ DEPOP_NONE,
+ DEPOP_LIST,
+ DEPOP_RESTORE,
+ DEPOP_REMOVE,
+};
+
+static int
+depop_list(struct cam_device *device, int task_attr, int retry_count,
+ int timeout, int verbosemode __unused)
+{
+ int error = 0;
+ uint32_t dtors;
+ struct scsi_get_physical_element_hdr *hdr;
+ struct scsi_get_physical_element_descriptor *dtor_ptr;
+
+ if (timeout == 0)
+ timeout = 30 * 1000;
+
+ hdr = scsi_wrap_get_physical_element_status(device, task_attr, retry_count, timeout,
+ SCSI_GPES_FILTER_ALL | SCSI_GPES_REPORT_TYPE_PHYS, 1);
+ if (hdr == NULL)
+ errx(1, "scsi_wrap_get_physical_element_status returned an error");
+
+ /*
+ * OK, we have the data, not report it out.
+ */
+ dtor_ptr = (struct scsi_get_physical_element_descriptor *)(hdr + 1);
+ dtors = scsi_4btoul(hdr->num_descriptors);
+ printf("Elem ID * Health Capacity\n");
+ for (uint32_t i = 0; i < dtors; i++) {
+ uint32_t id = scsi_4btoul(dtor_ptr[i].element_identifier);
+ uint8_t ralwd = dtor_ptr[i].ralwd;
+ uint8_t type = dtor_ptr[i].physical_element_type;
+ uint8_t health = dtor_ptr[i].physical_element_health;
+ uint64_t cap = scsi_8btou64(dtor_ptr[i].capacity);
+ if (type != GPED_TYPE_STORAGE)
+ printf("0x%08x -- type unknown %d\n", id, type);
+ else
+ printf("0x%08x %c 0x%02x %jd\n", id, ralwd ? '*' : ' ', health, cap);
+ }
+ printf("* -- Element can be restored\n");
+
+ free(hdr);
+ return (error);
+}
+
+static int
+depop_remove(struct cam_device *device, int task_attr, int retry_count,
+ int timeout, int verbosemode __unused, uint32_t elem, uint64_t capacity)
+{
+ union ccb *ccb;
+ int error = 0;
+
+ if (timeout == 0)
+ timeout = 30 * 1000;
+ ccb = cam_getccb(device);
+ if (ccb == NULL) {
+ warnx("Can't allocate ccb");
+ return (1);
+ }
+ scsi_remove_element_and_truncate(&ccb->csio,
+ retry_count,
+ NULL,
+ task_attr,
+ capacity,
+ elem,
+ SSD_FULL_SIZE,
+ timeout);
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+ if (cam_send_ccb(device, ccb) < 0) {
+ warn("error sending GET PHYSICAL ELEMENT STATUS command");
+ error = 1;
+ goto out;
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ error = 1;
+ }
+
+out:
+ cam_freeccb(ccb);
+ return (error);
+}
+
+static int
+depop_restore(struct cam_device *device, int task_attr, int retry_count,
+ int timeout, int verbosemode __unused)
+{
+ union ccb *ccb;
+ int error = 0;
+
+ if (timeout == 0)
+ timeout = 30 * 1000;
+ ccb = cam_getccb(device);
+ if (ccb == NULL) {
+ warnx("Can't allocate ccb");
+ return (1);
+ }
+ scsi_restore_elements_and_rebuild(&ccb->csio,
+ retry_count,
+ NULL,
+ task_attr,
+ SSD_FULL_SIZE,
+ timeout);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+ if (cam_send_ccb(device, ccb) < 0) {
+ warn("error sending GET PHYSICAL ELEMENT STATUS command");
+ error = 1;
+ goto out;
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ error = 1;
+ }
+
+out:
+ cam_freeccb(ccb);
+ return (error);
+}
+
+#define MUST_BE_NONE() \
+ if (action != DEPOP_NONE) { \
+ warnx("Use only one of -d, -l, or -r"); \
+ error = 1; \
+ goto bailout; \
+ }
+
+int
+depop(struct cam_device *device, int argc, char **argv, char *combinedopt,
+ int task_attr, int retry_count, int timeout, int verbosemode)
+{
+ int c;
+ int action = DEPOP_NONE;
+ char *endptr;
+ int error = 0;
+ uint32_t elem = 0;
+ uint64_t capacity = 0;
+
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch (c) {
+ case 'c':
+ capacity = strtoumax(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ warnx("Invalid capacity: %s", optarg);
+ error = 1;
+ goto bailout;
+ }
+ break;
+ case 'e':
+ elem = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ warnx("Invalid element: %s", optarg);
+ error = 1;
+ goto bailout;
+ }
+ break;
+ case 'd':
+ MUST_BE_NONE();
+ action = DEPOP_REMOVE;
+ break;
+ case 'l':
+ MUST_BE_NONE();
+ action = DEPOP_LIST;
+ break;
+ case 'r':
+ MUST_BE_NONE();
+ action = DEPOP_RESTORE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (action) {
+ case DEPOP_NONE:
+ warnx("Must specify one of -d, -l, or -r");
+ error = 1;
+ break;
+ case DEPOP_REMOVE:
+ if (elem == 0 && capacity == 0) {
+ warnx("Must specify at least one of -e and/or -c");
+ error = 1;
+ break;
+ }
+ error = depop_remove(device, task_attr, retry_count, timeout,
+ verbosemode, elem, capacity);
+ break;
+ case DEPOP_RESTORE:
+ error = depop_restore(device, task_attr, retry_count, timeout,
+ verbosemode);
+ break;
+ case DEPOP_LIST:
+ error = depop_list(device, task_attr, retry_count, timeout,
+ verbosemode);
+ break;
+ }
+
+bailout:
+
+ return (error);
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Jan 19, 5:43 PM (15 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15952934
Default Alt Text
D29018.id84996.diff (13 KB)

Event Timeline