diff options
-rw-r--r-- | drivers/scsi/3w-9xxx.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index bc6e4627c7a1..a6ac61611f35 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c | |||
@@ -59,6 +59,7 @@ | |||
59 | Fix 'handled=1' ISR usage, remove bogus IRQ check. | 59 | Fix 'handled=1' ISR usage, remove bogus IRQ check. |
60 | Remove un-needed eh_abort handler. | 60 | Remove un-needed eh_abort handler. |
61 | Add support for embedded firmware error strings. | 61 | Add support for embedded firmware error strings. |
62 | 2.26.02.003 - Correctly handle single sgl's with use_sg=1. | ||
62 | */ | 63 | */ |
63 | 64 | ||
64 | #include <linux/module.h> | 65 | #include <linux/module.h> |
@@ -81,7 +82,7 @@ | |||
81 | #include "3w-9xxx.h" | 82 | #include "3w-9xxx.h" |
82 | 83 | ||
83 | /* Globals */ | 84 | /* Globals */ |
84 | #define TW_DRIVER_VERSION "2.26.02.002" | 85 | #define TW_DRIVER_VERSION "2.26.02.003" |
85 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; | 86 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; |
86 | static unsigned int twa_device_extension_count; | 87 | static unsigned int twa_device_extension_count; |
87 | static int twa_major = -1; | 88 | static int twa_major = -1; |
@@ -1805,6 +1806,8 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, | |||
1805 | if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { | 1806 | if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { |
1806 | command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; | 1807 | command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; |
1807 | command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; | 1808 | command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; |
1809 | if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) | ||
1810 | memcpy(tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen); | ||
1808 | } else { | 1811 | } else { |
1809 | buffaddr = twa_map_scsi_single_data(tw_dev, request_id); | 1812 | buffaddr = twa_map_scsi_single_data(tw_dev, request_id); |
1810 | if (buffaddr == 0) | 1813 | if (buffaddr == 0) |
@@ -1823,6 +1826,12 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, | |||
1823 | 1826 | ||
1824 | if (tw_dev->srb[request_id]->use_sg > 0) { | 1827 | if (tw_dev->srb[request_id]->use_sg > 0) { |
1825 | if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { | 1828 | if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { |
1829 | if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) { | ||
1830 | struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; | ||
1831 | char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; | ||
1832 | memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length); | ||
1833 | kunmap_atomic(buf - sg->offset, KM_IRQ0); | ||
1834 | } | ||
1826 | command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; | 1835 | command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; |
1827 | command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; | 1836 | command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; |
1828 | } else { | 1837 | } else { |
@@ -1888,11 +1897,20 @@ out: | |||
1888 | /* This function completes an execute scsi operation */ | 1897 | /* This function completes an execute scsi operation */ |
1889 | static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id) | 1898 | static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id) |
1890 | { | 1899 | { |
1891 | /* Copy the response if too small */ | 1900 | if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH && |
1892 | if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { | 1901 | (tw_dev->srb[request_id]->sc_data_direction == DMA_FROM_DEVICE || |
1893 | memcpy(tw_dev->srb[request_id]->request_buffer, | 1902 | tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)) { |
1894 | tw_dev->generic_buffer_virt[request_id], | 1903 | if (tw_dev->srb[request_id]->use_sg == 0) { |
1895 | tw_dev->srb[request_id]->request_bufflen); | 1904 | memcpy(tw_dev->srb[request_id]->request_buffer, |
1905 | tw_dev->generic_buffer_virt[request_id], | ||
1906 | tw_dev->srb[request_id]->request_bufflen); | ||
1907 | } | ||
1908 | if (tw_dev->srb[request_id]->use_sg == 1) { | ||
1909 | struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; | ||
1910 | char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; | ||
1911 | memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length); | ||
1912 | kunmap_atomic(buf - sg->offset, KM_IRQ0); | ||
1913 | } | ||
1896 | } | 1914 | } |
1897 | } /* End twa_scsiop_execute_scsi_complete() */ | 1915 | } /* End twa_scsiop_execute_scsi_complete() */ |
1898 | 1916 | ||