Fix a performance problem with the ciss(4) driver. NetBSD does common

queueing at the scsipi midlayer, and if the midlayer is not requested to
enable tagged queueing, the midlayer will only queue one command to the
adapter driver for each device.  The SmartArray adapter is capable of
handling multiple commands, and in the rather common case where there is
no battery backup and no write cache, doing single write commands is very
slow.  The SmartArray adapter runs much better when several commands can
be issued to a device.

This has been observed and discussed in several list threads, notably:
http://mail-index.NetBSD.org/netbsd-users/2008/10/01/msg002083.html
http://mail-index.NetBSD.org/tech-kern/2008/11/30/msg003704.html

This also addresses PR kern/39686.

To enable tagged queueing, the adapter driver responds to the midlayer
request to set the transfer mode.  However, the SmartArray does not respond
to the SCSI INQUIRY command with an ANSII field of 2 or more, so the
scsipi midlayer will ignore the CmdQue bit in the flags3 field of the
inquiry data.  This fix will patch the inquiry data so set the ANSII field
to 2, and responds to the midlayer request to set the transfer mode by
requesting tagged queueing.

In addition, the original port of the driver did not set up the adapter
parameters correctly as mentioned in the second list thread mentioned
above.  The adapt_openings is the total number of commands that the
adapter will accept rather than the number of commands divided by the
number of logical drives.  Also, the adapt_max_periph is the maximum number
of commands which can be queued per peripheral device, not the number of
logical drives [which in the case of a single logical drive limited the
number of commands queued to 1].

I'm also suppressing an error message for invalid commands if the error
was due to the SCSI_SYNCHRONIZE_CACHE_10 command, since that command is
not supported by the SmartArray adapter, but used with wapbl(4) meta-data
journaling.  Setting the ANSII version to 2 to allow enabling tagged queueing
also enables the use of the SCSI_SYNCHRONIZE_CACHE_10 command.
This commit is contained in:
mhitch 2010-09-07 18:19:16 +00:00
parent d00164124d
commit 9c443068a6
1 changed files with 24 additions and 9 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ciss.c,v 1.22 2010/07/27 18:50:32 jakllsch Exp $ */
/* $NetBSD: ciss.c,v 1.23 2010/09/07 18:19:16 mhitch Exp $ */
/* $OpenBSD: ciss.c,v 1.14 2006/03/13 16:02:23 mickey Exp $ */
/*
@ -19,7 +19,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.22 2010/07/27 18:50:32 jakllsch Exp $");
__KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.23 2010/09/07 18:19:16 mhitch Exp $");
#include "bio.h"
@ -41,6 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.22 2010/07/27 18:50:32 jakllsch Exp $");
#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsi_disk.h>
#include <dev/scsipi/scsiconf.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/ic/cissreg.h>
#include <dev/ic/cissvar.h>
@ -363,7 +364,7 @@ ciss_attach(struct ciss_softc *sc)
sc->sc_channel.chan_channel = 0;
sc->sc_channel.chan_ntargets = sc->maxunits;
sc->sc_channel.chan_nluns = 1; /* ciss doesn't really have SCSI luns */
sc->sc_channel.chan_openings = sc->maxcmd / (sc->maxunits? sc->maxunits : 1);
sc->sc_channel.chan_openings = sc->maxcmd;
#if NBIO > 0
/* XXX Reserve some ccb's for sensor and bioctl. */
if (sc->sc_channel.chan_openings > 2)
@ -374,7 +375,7 @@ ciss_attach(struct ciss_softc *sc)
sc->sc_adapter.adapt_dev = (device_t) sc;
sc->sc_adapter.adapt_openings = sc->sc_channel.chan_openings;
sc->sc_adapter.adapt_max_periph = sc->maxunits;
sc->sc_adapter.adapt_max_periph = sc->sc_channel.chan_openings;
sc->sc_adapter.adapt_request = ciss_scsi_cmd;
sc->sc_adapter.adapt_minphys = cissminphys;
sc->sc_adapter.adapt_ioctl = ciss_scsi_ioctl;
@ -617,6 +618,14 @@ ciss_done(struct ciss_ccb *ccb)
if (xs) {
xs->resid = 0;
CISS_DPRINTF(CISS_D_CMD, ("scsipi_done(%p) ", xs));
if (xs->cmd->opcode == INQUIRY) {
struct scsipi_inquiry_data *inq;
inq = (struct scsipi_inquiry_data *)xs->data;
if ((inq->version & SID_ANSII) == 0 &&
(inq->flags3 & SID_CmdQue) != 0) {
inq->version |= 2;
}
}
scsipi_done(xs);
}
@ -636,9 +645,11 @@ ciss_error(struct ciss_ccb *ccb)
break;
case CISS_ERR_INVCMD:
printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n",
device_xname(&sc->sc_dev), ccb->ccb_cmd.id,
err->err_info, err->err_type[3], err->err_type[2]);
if (xs == NULL ||
xs->cmd->opcode != SCSI_SYNCHRONIZE_CACHE_10)
printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n",
device_xname(&sc->sc_dev), ccb->ccb_cmd.id,
err->err_info, err->err_type[3], err->err_type[2]);
if (xs) {
memset(&xs->sense, 0, sizeof(xs->sense));
xs->sense.scsi_sense.response_code =
@ -1002,7 +1013,8 @@ static void
ciss_scsi_cmd(struct scsipi_channel *chan, scsipi_adapter_req_t req,
void *arg)
{
struct scsipi_xfer *xs = (struct scsipi_xfer *) arg;
struct scsipi_xfer *xs;
struct scsipi_xfer_mode *xm;
struct ciss_softc *sc =
(struct ciss_softc *) chan->chan_adapter->adapt_dev;
u_int8_t target;
@ -1015,6 +1027,7 @@ ciss_scsi_cmd(struct scsipi_channel *chan, scsipi_adapter_req_t req,
switch (req)
{
case ADAPTER_REQ_RUN_XFER:
xs = (struct scsipi_xfer *) arg;
target = xs->xs_periph->periph_target;
CISS_DPRINTF(CISS_D_CMD, ("targ=%d ", target));
if (xs->cmdlen > CISS_MAX_CDB) {
@ -1072,7 +1085,9 @@ ciss_scsi_cmd(struct scsipi_channel *chan, scsipi_adapter_req_t req,
* We can't change the transfer mode, but at least let
* scsipi know what the adapter has negociated.
*/
/* FIXME: get xfer mode and write it into arg */
xm = (struct scsipi_xfer_mode *)arg;
xm->xm_mode |= PERIPH_CAP_TQING;
scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
break;
}
}