From 8f6b4e5b99cdee41cc97b1675eb0172531fd2112 Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Mon, 23 Feb 2009 23:18:25 +0000 Subject: [PATCH] Put some limit checking on dma segments so that we don't, somehow, inadvertantly overrun the total number of queue entries for a command + continuation segments. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@680 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla_isp/common/ispmbox.h | 15 +++++++++++++++ qla_isp/linux/isp_pci.c | 23 ++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/qla_isp/common/ispmbox.h b/qla_isp/common/ispmbox.h index 09d6ddbb3..f3b1647d4 100644 --- a/qla_isp/common/ispmbox.h +++ b/qla_isp/common/ispmbox.h @@ -2548,4 +2548,19 @@ typedef struct { #define ISP24XX_ABTS_RSP_SUBCODE 0x31 #define ISP24XX_NO_TASK 0xffffffff + +/* + * Miscellaneous + * + * These are the limits of the number of dma segments we + * can deal with based not on the size of the segment counter + * (which is 16 bits), but on the size of the number of + * queue entries field (which is 8 bits). We assume no + * segments in the first queue entry, so we can either + * have 7 dma segments per continuation entry or 5 + * (for 64 bit dma).. multiplying out by 254.... + */ +#define ISP_NSEG_MAX 1778 +#define ISP_NSEG64_MAX 1270 + #endif /* _ISPMBOX_H */ diff --git a/qla_isp/linux/isp_pci.c b/qla_isp/linux/isp_pci.c index 3ed717fd0..e0ce9a63b 100644 --- a/qla_isp/linux/isp_pci.c +++ b/qla_isp/linux/isp_pci.c @@ -1627,7 +1627,17 @@ isp_pci_dmasetup_tgt(ispsoftc_t *isp, tmd_xact_t *xact, void *fqe) sg = NULL; nseg = 0; } - + if (isp->isp_osinfo.is_64bit_dma) { + if (nseg >= ISP_NSEG64_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX); + xact->td_error = -EFAULT; + return (CMD_COMPLETE); + } + } else if (nseg >= ISP_NSEG_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX); + xact->td_error = -EFAULT; + return (CMD_COMPLETE); + } ret = isp_send_tgt_cmd(isp, fqe, sg, nseg, xact->td_xfrlen, ddir, xact->td_cmd->cd_sense, TMD_SENSELEN); if (ret == CMD_QUEUED) { int bin; @@ -1729,6 +1739,17 @@ isp_pci_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, void *fqe) sg = NULL; nseg = 0; } + if (isp->isp_osinfo.is_64bit_dma) { + if (nseg >= ISP_NSEG64_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX); + XS_SETERR(Cmnd, HBA_BOTCH); + return (CMD_COMPLETE); + } + } else if (nseg >= ISP_NSEG_MAX) { + isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX); + XS_SETERR(Cmnd, HBA_BOTCH); + return (CMD_COMPLETE); + } ret = isp_send_cmd(isp, fqe, sg, nseg, XS_XFRLEN(Cmnd), ddir); if (ret == CMD_QUEUED) { int bin;