Make delete method set via kern.cam.da.X.delete_method persistent.

This allows to set delete method via tunable, before device capabilities
are known.  Also allow ZERO method for devices not reporting LBP, if user
explicitly requests it -- it may be useful if storage supports compression
and WRITE SAME, but does not support UNMAP.

MFC after:	2 weeks
This commit is contained in:
Alexander Motin 2015-10-11 18:26:06 +00:00
parent eaccd9b323
commit 0ac03010f6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=289146
2 changed files with 55 additions and 48 deletions

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd October 22, 2014
.Dd October 11, 2015
.Dt DA 4
.Os
.Sh NAME
@ -133,8 +133,7 @@ variables and
.Xr loader 8
tunables:
.Bl -tag -width 12
.It kern.cam.da.retry_count
.Pp
.It Va kern.cam.da.retry_count
This variable determines how many times the
.Nm
driver will retry a READ or WRITE command.
@ -143,8 +142,7 @@ the
.Nm
driver dump routine.
This value currently defaults to 4.
.It kern.cam.da.default_timeout
.Pp
.It Va kern.cam.da.default_timeout
This variable determines how long the
.Nm
driver will wait before timing out an outstanding command.
@ -152,20 +150,31 @@ The units for this value are seconds, and the default is currently 60
seconds.
.It Va kern.cam.sort_io_queue
.It Va kern.cam.da. Ns Ar X Ns Va .sort_io_queue
.Pp
These variables determine whether request queue should be sorted trying
to optimize head seeks.
Set to 1 to enable sorting, 0 to disable, -1 to leave it as-is.
The default is sorting enabled for HDDs and disabled for SSDs.
.It kern.cam.da.%d.minimum_cmd_size
.Pp
.It Va kern.cam.da. Ns Ar X Ns Va .delete_method
This variable specifies method to handle BIO_DELETE requests:
.Bl -tag
.It ATA_TRIM
ATA TRIM via ATA COMMAND PASS THROUGH command,
.It UNMAP
UNMAP command,
.It WS16
WRITE SAME(16) command with UNMAP flag,
.It WS10
WRITE SAME(10) command with UNMAP flag,
.It ZERO
WRITE SAME(10) command without UNMAP flag,
.It DISABLE
disable BIO_DELETE support.
.El
.It Va kern.cam.da. Ns Ar X Ns Va .minimum_cmd_size
This variable determines what the minimum READ/WRITE CDB size is for a
given
.Nm
unit.
(The %d above denotes the unit number of the
.Nm
driver instance, e.g.\& 1, 2, 4, 8, etc.)
Valid minimum command size values are 6, 10, 12 and 16 bytes.
The default is 6 bytes.
.Pp

View File

@ -219,6 +219,7 @@ struct da_softc {
uint32_t unmap_max_ranges;
uint32_t unmap_max_lba; /* Max LBAs in UNMAP req */
uint64_t ws_max_blks;
da_delete_methods delete_method_pref;
da_delete_methods delete_method;
da_delete_func_t *delete_func;
struct disk_params params;
@ -1801,7 +1802,7 @@ dasysctlinit(void *context, int pending)
* the fly.
*/
SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
OID_AUTO, "delete_method", CTLTYPE_STRING | CTLFLAG_RW,
OID_AUTO, "delete_method", CTLTYPE_STRING | CTLFLAG_RWTUN,
softc, 0, dadeletemethodsysctl, "A",
"BIO_DELETE execution method");
SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
@ -1912,7 +1913,6 @@ static void
dadeletemethodset(struct da_softc *softc, da_delete_methods delete_method)
{
softc->delete_method = delete_method;
softc->disk->d_delmaxsize = dadeletemaxsize(softc, delete_method);
softc->delete_func = da_delete_functions[delete_method];
@ -1965,25 +1965,17 @@ daprobedone(struct cam_periph *periph, union ccb *ccb)
snprintf(buf, sizeof(buf), "Delete methods: <");
sep = 0;
for (i = DA_DELETE_MIN; i <= DA_DELETE_MAX; i++) {
if (softc->delete_available & (1 << i)) {
if (sep) {
strlcat(buf, ",", sizeof(buf));
} else {
sep = 1;
}
strlcat(buf, da_delete_method_names[i],
sizeof(buf));
if (i == softc->delete_method) {
strlcat(buf, "(*)", sizeof(buf));
}
}
}
if (sep == 0) {
if (softc->delete_method == DA_DELETE_NONE)
strlcat(buf, "NONE(*)", sizeof(buf));
else
strlcat(buf, "DISABLED(*)", sizeof(buf));
for (i = 0; i <= DA_DELETE_MAX; i++) {
if ((softc->delete_available & (1 << i)) == 0 &&
i != softc->delete_method)
continue;
if (sep)
strlcat(buf, ",", sizeof(buf));
strlcat(buf, da_delete_method_names[i],
sizeof(buf));
if (i == softc->delete_method)
strlcat(buf, "(*)", sizeof(buf));
sep = 1;
}
strlcat(buf, ">", sizeof(buf));
printf("%s%d: %s\n", periph->periph_name,
@ -2013,21 +2005,28 @@ daprobedone(struct cam_periph *periph, union ccb *ccb)
static void
dadeletemethodchoose(struct da_softc *softc, da_delete_methods default_method)
{
int i, delete_method;
int i, methods;
delete_method = default_method;
/* If available, prefer the method requested by user. */
i = softc->delete_method_pref;
methods = softc->delete_available | (1 << DA_DELETE_DISABLE);
if (methods & (1 << i)) {
dadeletemethodset(softc, i);
return;
}
/*
* Use the pre-defined order to choose the best
* performing delete.
*/
/* Use the pre-defined order to choose the best performing delete. */
for (i = DA_DELETE_MIN; i <= DA_DELETE_MAX; i++) {
if (i == DA_DELETE_ZERO)
continue;
if (softc->delete_available & (1 << i)) {
dadeletemethodset(softc, i);
return;
}
}
dadeletemethodset(softc, delete_method);
/* Fallback to default. */
dadeletemethodset(softc, default_method);
}
static int
@ -2051,13 +2050,14 @@ dadeletemethodsysctl(SYSCTL_HANDLER_ARGS)
return (error);
methods = softc->delete_available | (1 << DA_DELETE_DISABLE);
for (i = 0; i <= DA_DELETE_MAX; i++) {
if (!(methods & (1 << i)) ||
strcmp(buf, da_delete_method_names[i]) != 0)
continue;
dadeletemethodset(softc, i);
return (0);
if (strcmp(buf, da_delete_method_names[i]) == 0)
break;
}
return (EINVAL);
if (i > DA_DELETE_MAX)
return (EINVAL);
softc->delete_method_pref = i;
dadeletemethodchoose(softc, DA_DELETE_NONE);
return (0);
}
static cam_status
@ -3288,6 +3288,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
/* Ensure re-probe doesn't see old delete. */
softc->delete_available = 0;
dadeleteflag(softc, DA_DELETE_ZERO, 1);
if (lbp && (softc->quirks & DA_Q_NO_UNMAP) == 0) {
/*
* Based on older SBC-3 spec revisions
@ -3304,7 +3305,6 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
*/
dadeleteflag(softc, DA_DELETE_WS16, 1);
dadeleteflag(softc, DA_DELETE_WS10, 1);
dadeleteflag(softc, DA_DELETE_ZERO, 1);
dadeleteflag(softc, DA_DELETE_UNMAP, 1);
xpt_release_ccb(done_ccb);
@ -3333,8 +3333,6 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
(lbp->flags & SVPD_LBP_WS16));
dadeleteflag(softc, DA_DELETE_WS10,
(lbp->flags & SVPD_LBP_WS10));
dadeleteflag(softc, DA_DELETE_ZERO,
(lbp->flags & SVPD_LBP_WS10));
dadeleteflag(softc, DA_DELETE_UNMAP,
(lbp->flags & SVPD_LBP_UNMAP));
} else {