diff options
author | Rajashekhara, Mahesh <Mahesh_Rajashekhara@adaptec.com> | 2010-05-10 07:24:01 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-05-16 22:49:46 -0400 |
commit | da3cc679b247a22efe0746d129074015b278e64d (patch) | |
tree | 4949e9cabd0e3a7df4c840d3185af3a4a7a45849 /drivers/scsi/aacraid | |
parent | 1fc8010a5d9a27391db2be103b13f4ac80990cfc (diff) |
[SCSI] aacraid: prohibit access to array container space
Problem description:
--------------------
The issue reported by one of the customer was able to read LBA beyond
the array reported size with "sg_read" utility. If N is the last block
address reported, then should not be able to read past N,
i.e. N+1. But in their case, reported last LBA=143134719. So should
not have been able to read with LBA=143134720, but it is read without
failure, which means reported size to the OS is not correct and is
less than the actual last block address.
Solution:
---------
Firmware layer exposes lesser container capacity than the actual
one. It exposes [Actual size - Spitfire space(10MB)] to the OS, IO's
to the 10MB should be prohibited from the Linux driver. Driver checks
LBA boundary, if its greater than the array reported size then sets
sensekey to HARDWARE_ERROR and sends the notification to the MID
layer.
Signed-off-by: Mahesh Rajashekhara <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/aacraid')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index fdc7d9935aeb..7df2dd1d2c6f 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c | |||
@@ -1608,6 +1608,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) | |||
1608 | int status; | 1608 | int status; |
1609 | struct aac_dev *dev; | 1609 | struct aac_dev *dev; |
1610 | struct fib * cmd_fibcontext; | 1610 | struct fib * cmd_fibcontext; |
1611 | int cid; | ||
1611 | 1612 | ||
1612 | dev = (struct aac_dev *)scsicmd->device->host->hostdata; | 1613 | dev = (struct aac_dev *)scsicmd->device->host->hostdata; |
1613 | /* | 1614 | /* |
@@ -1657,6 +1658,22 @@ static int aac_read(struct scsi_cmnd * scsicmd) | |||
1657 | count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; | 1658 | count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; |
1658 | break; | 1659 | break; |
1659 | } | 1660 | } |
1661 | |||
1662 | if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { | ||
1663 | cid = scmd_id(scsicmd); | ||
1664 | dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); | ||
1665 | scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | | ||
1666 | SAM_STAT_CHECK_CONDITION; | ||
1667 | set_sense(&dev->fsa_dev[cid].sense_data, | ||
1668 | HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, | ||
1669 | ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); | ||
1670 | memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, | ||
1671 | min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), | ||
1672 | SCSI_SENSE_BUFFERSIZE)); | ||
1673 | scsicmd->scsi_done(scsicmd); | ||
1674 | return 1; | ||
1675 | } | ||
1676 | |||
1660 | dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", | 1677 | dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", |
1661 | smp_processor_id(), (unsigned long long)lba, jiffies)); | 1678 | smp_processor_id(), (unsigned long long)lba, jiffies)); |
1662 | if (aac_adapter_bounds(dev,scsicmd,lba)) | 1679 | if (aac_adapter_bounds(dev,scsicmd,lba)) |
@@ -1698,6 +1715,7 @@ static int aac_write(struct scsi_cmnd * scsicmd) | |||
1698 | int status; | 1715 | int status; |
1699 | struct aac_dev *dev; | 1716 | struct aac_dev *dev; |
1700 | struct fib * cmd_fibcontext; | 1717 | struct fib * cmd_fibcontext; |
1718 | int cid; | ||
1701 | 1719 | ||
1702 | dev = (struct aac_dev *)scsicmd->device->host->hostdata; | 1720 | dev = (struct aac_dev *)scsicmd->device->host->hostdata; |
1703 | /* | 1721 | /* |
@@ -1737,6 +1755,22 @@ static int aac_write(struct scsi_cmnd * scsicmd) | |||
1737 | count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; | 1755 | count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; |
1738 | fua = scsicmd->cmnd[1] & 0x8; | 1756 | fua = scsicmd->cmnd[1] & 0x8; |
1739 | } | 1757 | } |
1758 | |||
1759 | if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { | ||
1760 | cid = scmd_id(scsicmd); | ||
1761 | dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); | ||
1762 | scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | | ||
1763 | SAM_STAT_CHECK_CONDITION; | ||
1764 | set_sense(&dev->fsa_dev[cid].sense_data, | ||
1765 | HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, | ||
1766 | ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); | ||
1767 | memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, | ||
1768 | min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), | ||
1769 | SCSI_SENSE_BUFFERSIZE)); | ||
1770 | scsicmd->scsi_done(scsicmd); | ||
1771 | return 1; | ||
1772 | } | ||
1773 | |||
1740 | dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", | 1774 | dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", |
1741 | smp_processor_id(), (unsigned long long)lba, jiffies)); | 1775 | smp_processor_id(), (unsigned long long)lba, jiffies)); |
1742 | if (aac_adapter_bounds(dev,scsicmd,lba)) | 1776 | if (aac_adapter_bounds(dev,scsicmd,lba)) |