Commit 138125f7 authored by Al Viro's avatar Al Viro Committed by Martin K. Petersen
Browse files

scsi: hpsa: Lift {BIG_,}IOCTL_Command_struct copy{in,out} into hpsa_ioctl()

parent 7b6668d8
Loading
Loading
Loading
Loading
+56 −60
Original line number Diff line number Diff line
@@ -6358,37 +6358,33 @@ static int hpsa_getdrivver_ioctl(struct ctlr_info *h, void __user *argp)
	return 0;
}

static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
static int hpsa_passthru_ioctl(struct ctlr_info *h,
			       IOCTL_Command_struct *iocommand)
{
	IOCTL_Command_struct iocommand;
	struct CommandList *c;
	char *buff = NULL;
	u64 temp64;
	int rc = 0;

	if (!argp)
		return -EINVAL;
	if (!capable(CAP_SYS_RAWIO))
		return -EPERM;
	if (copy_from_user(&iocommand, argp, sizeof(iocommand)))
		return -EFAULT;
	if ((iocommand.buf_size < 1) &&
	    (iocommand.Request.Type.Direction != XFER_NONE)) {
	if ((iocommand->buf_size < 1) &&
	    (iocommand->Request.Type.Direction != XFER_NONE)) {
		return -EINVAL;
	}
	if (iocommand.buf_size > 0) {
		buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
	if (iocommand->buf_size > 0) {
		buff = kmalloc(iocommand->buf_size, GFP_KERNEL);
		if (buff == NULL)
			return -ENOMEM;
		if (iocommand.Request.Type.Direction & XFER_WRITE) {
		if (iocommand->Request.Type.Direction & XFER_WRITE) {
			/* Copy the data into the buffer we created */
			if (copy_from_user(buff, iocommand.buf,
				iocommand.buf_size)) {
			if (copy_from_user(buff, iocommand->buf,
				iocommand->buf_size)) {
				rc = -EFAULT;
				goto out_kfree;
			}
		} else {
			memset(buff, 0, iocommand.buf_size);
			memset(buff, 0, iocommand->buf_size);
		}
	}
	c = cmd_alloc(h);
@@ -6398,23 +6394,23 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
	c->scsi_cmd = SCSI_CMD_BUSY;
	/* Fill in Command Header */
	c->Header.ReplyQueue = 0; /* unused in simple mode */
	if (iocommand.buf_size > 0) {	/* buffer to fill */
	if (iocommand->buf_size > 0) {	/* buffer to fill */
		c->Header.SGList = 1;
		c->Header.SGTotal = cpu_to_le16(1);
	} else	{ /* no buffers to fill */
		c->Header.SGList = 0;
		c->Header.SGTotal = cpu_to_le16(0);
	}
	memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN));
	memcpy(&c->Header.LUN, &iocommand->LUN_info, sizeof(c->Header.LUN));

	/* Fill in Request block */
	memcpy(&c->Request, &iocommand.Request,
	memcpy(&c->Request, &iocommand->Request,
		sizeof(c->Request));

	/* Fill in the scatter gather information */
	if (iocommand.buf_size > 0) {
	if (iocommand->buf_size > 0) {
		temp64 = dma_map_single(&h->pdev->dev, buff,
			iocommand.buf_size, DMA_BIDIRECTIONAL);
			iocommand->buf_size, DMA_BIDIRECTIONAL);
		if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) {
			c->SG[0].Addr = cpu_to_le64(0);
			c->SG[0].Len = cpu_to_le32(0);
@@ -6422,12 +6418,12 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
			goto out;
		}
		c->SG[0].Addr = cpu_to_le64(temp64);
		c->SG[0].Len = cpu_to_le32(iocommand.buf_size);
		c->SG[0].Len = cpu_to_le32(iocommand->buf_size);
		c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */
	}
	rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
					NO_TIMEOUT);
	if (iocommand.buf_size > 0)
	if (iocommand->buf_size > 0)
		hpsa_pci_unmap(h->pdev, c, 1, DMA_BIDIRECTIONAL);
	check_ioctl_unit_attention(h, c);
	if (rc) {
@@ -6436,16 +6432,12 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
	}

	/* Copy the error information out */
	memcpy(&iocommand.error_info, c->err_info,
		sizeof(iocommand.error_info));
	if (copy_to_user(argp, &iocommand, sizeof(iocommand))) {
		rc = -EFAULT;
		goto out;
	}
	if ((iocommand.Request.Type.Direction & XFER_READ) &&
		iocommand.buf_size > 0) {
	memcpy(&iocommand->error_info, c->err_info,
		sizeof(iocommand->error_info));
	if ((iocommand->Request.Type.Direction & XFER_READ) &&
		iocommand->buf_size > 0) {
		/* Copy the data out of the buffer we created */
		if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
		if (copy_to_user(iocommand->buf, buff, iocommand->buf_size)) {
			rc = -EFAULT;
			goto out;
		}
@@ -6457,9 +6449,9 @@ out_kfree:
	return rc;
}

static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
static int hpsa_big_passthru_ioctl(struct ctlr_info *h,
				   BIG_IOCTL_Command_struct *ioc)
{
	BIG_IOCTL_Command_struct *ioc;
	struct CommandList *c;
	unsigned char **buff = NULL;
	int *buff_size = NULL;
@@ -6470,29 +6462,17 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
	u32 sz;
	BYTE __user *data_ptr;

	if (!argp)
		return -EINVAL;
	if (!capable(CAP_SYS_RAWIO))
		return -EPERM;
	ioc = vmemdup_user(argp, sizeof(*ioc));
	if (IS_ERR(ioc)) {
		status = PTR_ERR(ioc);
		goto cleanup1;
	}

	if ((ioc->buf_size < 1) &&
	    (ioc->Request.Type.Direction != XFER_NONE)) {
		status = -EINVAL;
		goto cleanup1;
	}
	    (ioc->Request.Type.Direction != XFER_NONE))
		return -EINVAL;
	/* Check kmalloc limits  using all SGs */
	if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
		status = -EINVAL;
		goto cleanup1;
	}
	if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD) {
		status = -EINVAL;
		goto cleanup1;
	}
	if (ioc->malloc_size > MAX_KMALLOC_SIZE)
		return -EINVAL;
	if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD)
		return -EINVAL;
	buff = kcalloc(SG_ENTRIES_IN_CMD, sizeof(char *), GFP_KERNEL);
	if (!buff) {
		status = -ENOMEM;
@@ -6565,10 +6545,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)

	/* Copy the error information out */
	memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info));
	if (copy_to_user(argp, ioc, sizeof(*ioc))) {
		status = -EFAULT;
		goto cleanup0;
	}
	if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) {
		int i;

@@ -6594,7 +6570,6 @@ cleanup1:
		kfree(buff);
	}
	kfree(buff_size);
	kvfree(ioc);
	return status;
}

@@ -6628,18 +6603,39 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
		return hpsa_getpciinfo_ioctl(h, argp);
	case CCISS_GETDRIVVER:
		return hpsa_getdrivver_ioctl(h, argp);
	case CCISS_PASSTHRU:
	case CCISS_PASSTHRU: {
		IOCTL_Command_struct iocommand;

		if (!argp)
			return -EINVAL;
		if (copy_from_user(&iocommand, argp, sizeof(iocommand)))
			return -EFAULT;
		if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
			return -EAGAIN;
		rc = hpsa_passthru_ioctl(h, argp);
		rc = hpsa_passthru_ioctl(h, &iocommand);
		atomic_inc(&h->passthru_cmds_avail);
		if (!rc && copy_to_user(argp, &iocommand, sizeof(iocommand)))
			rc = -EFAULT;
		return rc;
	case CCISS_BIG_PASSTHRU:
	}
	case CCISS_BIG_PASSTHRU: {
		BIG_IOCTL_Command_struct *ioc;
		if (!argp)
			return -EINVAL;
		if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
			return -EAGAIN;
		rc = hpsa_big_passthru_ioctl(h, argp);
		ioc = vmemdup_user(argp, sizeof(*ioc));
		if (IS_ERR(ioc)) {
			atomic_inc(&h->passthru_cmds_avail);
			return PTR_ERR(ioc);
		}
		rc = hpsa_big_passthru_ioctl(h, ioc);
		atomic_inc(&h->passthru_cmds_avail);
		if (!rc && copy_to_user(argp, ioc, sizeof(*ioc)))
			rc = -EFAULT;
		kvfree(ioc);
		return rc;
	}
	default:
		return -ENOTTY;
	}