diff --git a/sys/dev/raid/hptiop/hptiop.c b/sys/dev/raid/hptiop/hptiop.c --- a/sys/dev/raid/hptiop/hptiop.c +++ b/sys/dev/raid/hptiop/hptiop.c @@ -68,6 +68,9 @@ #include +/* Maximum scatter/gather entries the driver will build per request. */ +#define HPTIOP_MAX_SG_COUNT 64 + static const char driver_name[] = "hptiop"; static const char driver_version[] = "v1.8"; @@ -1931,6 +1934,8 @@ hba->max_devices = iop_config.max_devices; hba->max_request_size = iop_config.request_size; hba->max_sg_count = iop_config.max_sg_count; + if (hba->max_sg_count == 0 || hba->max_sg_count > HPTIOP_MAX_SG_COUNT) + hba->max_sg_count = HPTIOP_MAX_SG_COUNT; if (hba->ops->family == MVFREY_BASED_IOP) { if (hba->ops->internal_memalloc(hba)) { @@ -2416,7 +2421,10 @@ if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS) { u_int32_t iop_req32; - struct hpt_iop_request_scsi_command req; + u_int8_t req_buf[sizeof(struct hpt_iop_request_scsi_command) + + (HPTIOP_MAX_SG_COUNT - 1) * sizeof(struct hpt_iopsg)]; + struct hpt_iop_request_scsi_command *req = + (struct hpt_iop_request_scsi_command *)req_buf; iop_req32 = BUS_SPACE_RD4_ITL(inbound_queue); @@ -2430,7 +2438,7 @@ } if (ccb->csio.dxfer_len && nsegs > 0) { - struct hpt_iopsg *psg = req.sg_list; + struct hpt_iopsg *psg = req->sg_list; for (idx = 0; idx < nsegs; idx++, psg++) { psg->pci_address = (u_int64_t)segs[idx].ds_addr; psg->size = segs[idx].ds_len; @@ -2439,22 +2447,22 @@ psg[-1].eot = 1; } - bcopy(cdb, req.cdb, ccb->csio.cdb_len); + bcopy(cdb, req->cdb, min(ccb->csio.cdb_len, sizeof(req->cdb))); - req.header.size = + req->header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list) + nsegs*sizeof(struct hpt_iopsg); - req.header.type = IOP_REQUEST_TYPE_SCSI_COMMAND; - req.header.flags = 0; - req.header.result = IOP_RESULT_PENDING; - req.header.context = (u_int64_t)(unsigned long)srb; - req.dataxfer_length = ccb->csio.dxfer_len; - req.channel = 0; - req.target = ccb->ccb_h.target_id; - req.lun = ccb->ccb_h.target_lun; + req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND; + req->header.flags = 0; + req->header.result = IOP_RESULT_PENDING; + req->header.context = (u_int64_t)(unsigned long)srb; + req->dataxfer_length = ccb->csio.dxfer_len; + req->channel = 0; + req->target = ccb->ccb_h.target_id; + req->lun = ccb->ccb_h.target_lun; bus_space_write_region_1(hba->bar0t, hba->bar0h, iop_req32, - (u_int8_t *)&req, req.header.size); + (u_int8_t *)req, req->header.size); if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { bus_dmamap_sync(hba->io_dmat,