diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 212 |
1 files changed, 101 insertions, 111 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5abdce3ef70b..076dbcfa9471 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -1398,6 +1398,106 @@ static int cciss_getluninfo(ctlr_info_t *h, | |||
1398 | return 0; | 1398 | return 0; |
1399 | } | 1399 | } |
1400 | 1400 | ||
1401 | static int cciss_passthru(ctlr_info_t *h, void __user *argp) | ||
1402 | { | ||
1403 | IOCTL_Command_struct iocommand; | ||
1404 | CommandList_struct *c; | ||
1405 | char *buff = NULL; | ||
1406 | u64bit temp64; | ||
1407 | DECLARE_COMPLETION_ONSTACK(wait); | ||
1408 | |||
1409 | if (!argp) | ||
1410 | return -EINVAL; | ||
1411 | |||
1412 | if (!capable(CAP_SYS_RAWIO)) | ||
1413 | return -EPERM; | ||
1414 | |||
1415 | if (copy_from_user | ||
1416 | (&iocommand, argp, sizeof(IOCTL_Command_struct))) | ||
1417 | return -EFAULT; | ||
1418 | if ((iocommand.buf_size < 1) && | ||
1419 | (iocommand.Request.Type.Direction != XFER_NONE)) { | ||
1420 | return -EINVAL; | ||
1421 | } | ||
1422 | if (iocommand.buf_size > 0) { | ||
1423 | buff = kmalloc(iocommand.buf_size, GFP_KERNEL); | ||
1424 | if (buff == NULL) | ||
1425 | return -EFAULT; | ||
1426 | } | ||
1427 | if (iocommand.Request.Type.Direction == XFER_WRITE) { | ||
1428 | /* Copy the data into the buffer we created */ | ||
1429 | if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) { | ||
1430 | kfree(buff); | ||
1431 | return -EFAULT; | ||
1432 | } | ||
1433 | } else { | ||
1434 | memset(buff, 0, iocommand.buf_size); | ||
1435 | } | ||
1436 | c = cmd_special_alloc(h); | ||
1437 | if (!c) { | ||
1438 | kfree(buff); | ||
1439 | return -ENOMEM; | ||
1440 | } | ||
1441 | /* Fill in the command type */ | ||
1442 | c->cmd_type = CMD_IOCTL_PEND; | ||
1443 | /* Fill in Command Header */ | ||
1444 | c->Header.ReplyQueue = 0; /* unused in simple mode */ | ||
1445 | if (iocommand.buf_size > 0) { /* buffer to fill */ | ||
1446 | c->Header.SGList = 1; | ||
1447 | c->Header.SGTotal = 1; | ||
1448 | } else { /* no buffers to fill */ | ||
1449 | c->Header.SGList = 0; | ||
1450 | c->Header.SGTotal = 0; | ||
1451 | } | ||
1452 | c->Header.LUN = iocommand.LUN_info; | ||
1453 | /* use the kernel address the cmd block for tag */ | ||
1454 | c->Header.Tag.lower = c->busaddr; | ||
1455 | |||
1456 | /* Fill in Request block */ | ||
1457 | c->Request = iocommand.Request; | ||
1458 | |||
1459 | /* Fill in the scatter gather information */ | ||
1460 | if (iocommand.buf_size > 0) { | ||
1461 | temp64.val = pci_map_single(h->pdev, buff, | ||
1462 | iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); | ||
1463 | c->SG[0].Addr.lower = temp64.val32.lower; | ||
1464 | c->SG[0].Addr.upper = temp64.val32.upper; | ||
1465 | c->SG[0].Len = iocommand.buf_size; | ||
1466 | c->SG[0].Ext = 0; /* we are not chaining */ | ||
1467 | } | ||
1468 | c->waiting = &wait; | ||
1469 | |||
1470 | enqueue_cmd_and_start_io(h, c); | ||
1471 | wait_for_completion(&wait); | ||
1472 | |||
1473 | /* unlock the buffers from DMA */ | ||
1474 | temp64.val32.lower = c->SG[0].Addr.lower; | ||
1475 | temp64.val32.upper = c->SG[0].Addr.upper; | ||
1476 | pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size, | ||
1477 | PCI_DMA_BIDIRECTIONAL); | ||
1478 | check_ioctl_unit_attention(h, c); | ||
1479 | |||
1480 | /* Copy the error information out */ | ||
1481 | iocommand.error_info = *(c->err_info); | ||
1482 | if (copy_to_user(argp, &iocommand, sizeof(IOCTL_Command_struct))) { | ||
1483 | kfree(buff); | ||
1484 | cmd_special_free(h, c); | ||
1485 | return -EFAULT; | ||
1486 | } | ||
1487 | |||
1488 | if (iocommand.Request.Type.Direction == XFER_READ) { | ||
1489 | /* Copy the data out of the buffer we created */ | ||
1490 | if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { | ||
1491 | kfree(buff); | ||
1492 | cmd_special_free(h, c); | ||
1493 | return -EFAULT; | ||
1494 | } | ||
1495 | } | ||
1496 | kfree(buff); | ||
1497 | cmd_special_free(h, c); | ||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1401 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | 1501 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, |
1402 | unsigned int cmd, unsigned long arg) | 1502 | unsigned int cmd, unsigned long arg) |
1403 | { | 1503 | { |
@@ -1433,117 +1533,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | |||
1433 | case CCISS_GETLUNINFO: | 1533 | case CCISS_GETLUNINFO: |
1434 | return cciss_getluninfo(h, disk, argp); | 1534 | return cciss_getluninfo(h, disk, argp); |
1435 | case CCISS_PASSTHRU: | 1535 | case CCISS_PASSTHRU: |
1436 | { | 1536 | return cciss_passthru(h, argp); |
1437 | IOCTL_Command_struct iocommand; | ||
1438 | CommandList_struct *c; | ||
1439 | char *buff = NULL; | ||
1440 | u64bit temp64; | ||
1441 | DECLARE_COMPLETION_ONSTACK(wait); | ||
1442 | |||
1443 | if (!arg) | ||
1444 | return -EINVAL; | ||
1445 | |||
1446 | if (!capable(CAP_SYS_RAWIO)) | ||
1447 | return -EPERM; | ||
1448 | |||
1449 | if (copy_from_user | ||
1450 | (&iocommand, argp, sizeof(IOCTL_Command_struct))) | ||
1451 | return -EFAULT; | ||
1452 | if ((iocommand.buf_size < 1) && | ||
1453 | (iocommand.Request.Type.Direction != XFER_NONE)) { | ||
1454 | return -EINVAL; | ||
1455 | } | ||
1456 | #if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */ | ||
1457 | /* Check kmalloc limits */ | ||
1458 | if (iocommand.buf_size > 128000) | ||
1459 | return -EINVAL; | ||
1460 | #endif | ||
1461 | if (iocommand.buf_size > 0) { | ||
1462 | buff = kmalloc(iocommand.buf_size, GFP_KERNEL); | ||
1463 | if (buff == NULL) | ||
1464 | return -EFAULT; | ||
1465 | } | ||
1466 | if (iocommand.Request.Type.Direction == XFER_WRITE) { | ||
1467 | /* Copy the data into the buffer we created */ | ||
1468 | if (copy_from_user | ||
1469 | (buff, iocommand.buf, iocommand.buf_size)) { | ||
1470 | kfree(buff); | ||
1471 | return -EFAULT; | ||
1472 | } | ||
1473 | } else { | ||
1474 | memset(buff, 0, iocommand.buf_size); | ||
1475 | } | ||
1476 | c = cmd_special_alloc(h); | ||
1477 | if (!c) { | ||
1478 | kfree(buff); | ||
1479 | return -ENOMEM; | ||
1480 | } | ||
1481 | /* Fill in the command type */ | ||
1482 | c->cmd_type = CMD_IOCTL_PEND; | ||
1483 | /* Fill in Command Header */ | ||
1484 | c->Header.ReplyQueue = 0; /* unused in simple mode */ | ||
1485 | if (iocommand.buf_size > 0) /* buffer to fill */ | ||
1486 | { | ||
1487 | c->Header.SGList = 1; | ||
1488 | c->Header.SGTotal = 1; | ||
1489 | } else /* no buffers to fill */ | ||
1490 | { | ||
1491 | c->Header.SGList = 0; | ||
1492 | c->Header.SGTotal = 0; | ||
1493 | } | ||
1494 | c->Header.LUN = iocommand.LUN_info; | ||
1495 | /* use the kernel address the cmd block for tag */ | ||
1496 | c->Header.Tag.lower = c->busaddr; | ||
1497 | |||
1498 | /* Fill in Request block */ | ||
1499 | c->Request = iocommand.Request; | ||
1500 | |||
1501 | /* Fill in the scatter gather information */ | ||
1502 | if (iocommand.buf_size > 0) { | ||
1503 | temp64.val = pci_map_single(h->pdev, buff, | ||
1504 | iocommand.buf_size, | ||
1505 | PCI_DMA_BIDIRECTIONAL); | ||
1506 | c->SG[0].Addr.lower = temp64.val32.lower; | ||
1507 | c->SG[0].Addr.upper = temp64.val32.upper; | ||
1508 | c->SG[0].Len = iocommand.buf_size; | ||
1509 | c->SG[0].Ext = 0; /* we are not chaining */ | ||
1510 | } | ||
1511 | c->waiting = &wait; | ||
1512 | |||
1513 | enqueue_cmd_and_start_io(h, c); | ||
1514 | wait_for_completion(&wait); | ||
1515 | |||
1516 | /* unlock the buffers from DMA */ | ||
1517 | temp64.val32.lower = c->SG[0].Addr.lower; | ||
1518 | temp64.val32.upper = c->SG[0].Addr.upper; | ||
1519 | pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, | ||
1520 | iocommand.buf_size, | ||
1521 | PCI_DMA_BIDIRECTIONAL); | ||
1522 | |||
1523 | check_ioctl_unit_attention(h, c); | ||
1524 | |||
1525 | /* Copy the error information out */ | ||
1526 | iocommand.error_info = *(c->err_info); | ||
1527 | if (copy_to_user | ||
1528 | (argp, &iocommand, sizeof(IOCTL_Command_struct))) { | ||
1529 | kfree(buff); | ||
1530 | cmd_special_free(h, c); | ||
1531 | return -EFAULT; | ||
1532 | } | ||
1533 | |||
1534 | if (iocommand.Request.Type.Direction == XFER_READ) { | ||
1535 | /* Copy the data out of the buffer we created */ | ||
1536 | if (copy_to_user | ||
1537 | (iocommand.buf, buff, iocommand.buf_size)) { | ||
1538 | kfree(buff); | ||
1539 | cmd_special_free(h, c); | ||
1540 | return -EFAULT; | ||
1541 | } | ||
1542 | } | ||
1543 | kfree(buff); | ||
1544 | cmd_special_free(h, c); | ||
1545 | return 0; | ||
1546 | } | ||
1547 | case CCISS_BIG_PASSTHRU:{ | 1537 | case CCISS_BIG_PASSTHRU:{ |
1548 | BIG_IOCTL_Command_struct *ioc; | 1538 | BIG_IOCTL_Command_struct *ioc; |
1549 | CommandList_struct *c; | 1539 | CommandList_struct *c; |