[SCSI] 3ware 9000: handle use_sg != 0 for emulated commands

The attached patch updates the driver for the 3ware 9000 series to do
the following:

- Correctly handle single sgl's with use_sg = 1.

This is needed with the latest scsi-block-2.6 merge otherwise the 3w-9xxx
driver will not work. I tested the patch James sent a few weeks back to fix
this, and it had a bug where the request_buffer was accessed in
twa_scsiop_execute_scsi_complete() when it was invalid. This is a corrected
variation of that patch.

Signed-off-by: Adam Radford <linuxraid@amcc.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

authored by

adam radford and committed by
James Bottomley
d327d082 c7ebbbce

+24 -6
+24 -6
drivers/scsi/3w-9xxx.c
··· 59 59 Fix 'handled=1' ISR usage, remove bogus IRQ check. 60 60 Remove un-needed eh_abort handler. 61 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 65 #include <linux/module.h> ··· 82 81 #include "3w-9xxx.h" 83 82 84 83 /* Globals */ 85 - #define TW_DRIVER_VERSION "2.26.02.002" 84 + #define TW_DRIVER_VERSION "2.26.02.003" 86 85 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; 87 86 static unsigned int twa_device_extension_count; 88 87 static int twa_major = -1; ··· 1806 1805 if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { 1807 1806 command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; 1808 1807 command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; 1808 + if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) 1809 + memcpy(tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen); 1809 1810 } else { 1810 1811 buffaddr = twa_map_scsi_single_data(tw_dev, request_id); 1811 1812 if (buffaddr == 0) ··· 1826 1823 1827 1824 if (tw_dev->srb[request_id]->use_sg > 0) { 1828 1825 if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { 1826 + if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) { 1827 + struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; 1828 + char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; 1829 + memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length); 1830 + kunmap_atomic(buf - sg->offset, KM_IRQ0); 1831 + } 1829 1832 command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; 1830 1833 command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; 1831 1834 } else { ··· 1897 1888 /* This function completes an execute scsi operation */ 1898 1889 static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id) 1899 1890 { 1900 - /* Copy the response if too small */ 1901 - if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { 1902 - memcpy(tw_dev->srb[request_id]->request_buffer, 1903 - tw_dev->generic_buffer_virt[request_id], 1904 - tw_dev->srb[request_id]->request_bufflen); 1891 + if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH && 1892 + (tw_dev->srb[request_id]->sc_data_direction == DMA_FROM_DEVICE || 1893 + tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)) { 1894 + if (tw_dev->srb[request_id]->use_sg == 0) { 1895 + memcpy(tw_dev->srb[request_id]->request_buffer, 1896 + tw_dev->generic_buffer_virt[request_id], 1897 + tw_dev->srb[request_id]->request_bufflen); 1898 + } 1899 + if (tw_dev->srb[request_id]->use_sg == 1) { 1900 + struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; 1901 + char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; 1902 + memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length); 1903 + kunmap_atomic(buf - sg->offset, KM_IRQ0); 1904 + } 1905 1905 } 1906 1906 } /* End twa_scsiop_execute_scsi_complete() */ 1907 1907