--- a/sys/dev/disk/ncr/ncr.c +++ b/sys/dev/disk/ncr/ncr.c @@ -4090,6 +4090,20 @@ ncr_action (struct cam_sim *sim, union ccb *ccb) /* ** command */ /* XXX JGibbs - Support other command types */ + /* + ** DF-3608: the 53C8xx DMA engine and every descriptor we + ** build for it (struct link, struct scr_tblmove, squeue[]) + ** are 32-bit. On amd64 with memory above 4GB, silently + ** truncating vtophys() results makes the chip transfer to + ** the wrong physical memory. Refuse anything that does + ** not fit, instead of corrupting memory. + */ + if (((u_int64_t)vtophys (csio->cdb_io.cdb_bytes) >> 32) != 0 + || ((u_int64_t)vtophys (&csio->sense_data) >> 32) != 0) { + ccb->ccb_h.status = CAM_REQ_TOO_BIG; + ncr_free_nccb (np, cp); + crit_exit (); + xpt_done (ccb); + return; + } cp->phys.cmd.addr = vtophys (csio->cdb_io.cdb_bytes); cp->phys.cmd.size = csio->cdb_len; @@ -6564,7 +6578,17 @@ ncr_alloc_nccb (ncb_p np, u_long target, u_long lun) /* ** Allocate a nccb */ - cp = kmalloc (sizeof (struct nccb), M_DEVBUF, M_WAITOK | M_ZERO); + /* + ** DF-3608: keep the nccb below 4GB: cp->p_nccb / CCB_PHYS() + ** feed 32-bit script descriptors (jump_nccb.l_paddr, squeue[]). + */ + cp = kmem_alloc_contig (round_page(sizeof (struct nccb)), 0, + 0ul, 0xfffffffful, PAGE_SIZE); + if (cp != NULL) + bzero (cp, sizeof (struct nccb)); if (DEBUG_FLAGS & DEBUG_ALLOC) { kprintf ("new nccb @%p.\n", cp); --- a/sys/dev/disk/ncr/ncr.c +++ b/sys/dev/disk/ncr/ncr.c @@ -6700,6 +6700,13 @@ ncr_scatter phys->data[segment].addr = segaddr; phys->data[segment].size = segsize; segment++; + /* + ** DF-3608: reject segments whose physical address cannot + ** be represented in the 32-bit scr_tblmove.addr field. + */ + if (((u_int64_t)segaddr >> 32) != 0) + return (-1); } if (datalen) {