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 | ||
