summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ciss/ciss.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c
index d4c3583..1dcf88b 100644
--- a/sys/dev/ciss/ciss.c
+++ b/sys/dev/ciss/ciss.c
@@ -2985,6 +2985,7 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
case XPT_PATH_INQ:
{
struct ccb_pathinq *cpi = &ccb->cpi;
+ int sg_length;
debug(1, "XPT_PATH_INQ %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
@@ -3005,7 +3006,22 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
cpi->transport_version = 2;
cpi->protocol = PROTO_SCSI;
cpi->protocol_version = SCSI_REV_2;
- cpi->maxio = (min(CISS_MAX_SG_ELEMENTS - 1, sc->ciss_cfg->max_sg_length)) * PAGE_SIZE;
+ if (sc->ciss_cfg->max_sg_length == 0) {
+ sg_length = 16;
+ } else {
+ /* XXX Fix for ZMR cards that advertise max_sg_length == 32
+ * Confusing bit here. max_sg_length is usually a power of 2. We always
+ * need to subtract 1 to account for partial pages. Then we need to
+ * align on a valid PAGE_SIZE so we round down to the nearest power of 2.
+ * Add 1 so we can then subtract it out in the assignment to maxio.
+ * The reason for all these shenanigans is to create a maxio value that
+ * creates IO operations to volumes that yield consistent operations
+ * with good performance.
+ */
+ sg_length = sc->ciss_cfg->max_sg_length - 1;
+ sg_length = (1 << (fls(sg_length) - 1)) + 1;
+ }
+ cpi->maxio = (min(CISS_MAX_SG_ELEMENTS, sg_length) - 1) * PAGE_SIZE;
ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
OpenPOWER on IntegriCloud