3ware 9000 driver update for 2.6.13-git10
adam radford
maintainerPATCH 1/1 3ware 9000 driver update for 2.6.13-git10
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.
James, Please apply
Thanks!
Note: The patch is attached as an attachment, and also included
in-line below. The below
may have line-wrap issues since I'm pasting into gmail.
diff -Naur linux-2.6.13-git9/drivers/scsi/3w-9xxx.c linux-2.6.13-git10/drivers/scsi/3w-9xxx.c
--- linux-2.6.13-git9/drivers/scsi/3w-9xxx.c 2005-08-28 16:41:01.000000000 -0700
+++ linux-2.6.13-git10/drivers/scsi/3w-9xxx.c 2005-09-09
15:37:34.000000000 -0700
@@ -59,6 +59,7 @@
Fix 'handled=1' ISR usage, remove bogus IRQ check. Remove un-needed eh_abort handler.
Add support for embedded firmware error strings.
+ 2.26.02.003 - Correctly handle single sgl's with use_sg=1.
*/
#include <linux/module.h>
@@ -81,7 +82,7 @@
#include "3w-9xxx.h"
/* Globals */
-#define TW_DRIVER_VERSION "2.26.02.002"
+#define TW_DRIVER_VERSION "2.26.02.003"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
@@ -1805,6 +1806,8 @@
if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
command_packet->sg_list[0].address =
tw_dev->generic_buffer_phys[request_id];
command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+ if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE
|| tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)
+ memcpy(tw_dev->generic_buffer_virt[request_id],
tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
} else {
buffaddr = twa_map_scsi_single_data(tw_dev, request_id); if (buffaddr == 0)
@@ -1823,6 +1826,12 @@
if (tw_dev->srb[request_id]->use_sg > 0) {
if ((tw_dev->srb[request_id]->use_sg == 1) &&
(tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+ if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE
|| tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) {
+ struct scatterlist *sg = (struct scatterlist
*)tw_dev->srb[request_id]->request_buffer;
+ char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ }
command_packet->sg_list[0].address =
tw_dev->generic_buffer_phys[request_id];
command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
} else {
@@ -1888,11 +1897,20 @@
/* This function completes an execute scsi operation */
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension*tw_dev, int request_id)
{
- /* Copy the response if too small */
- if ((tw_dev->srb[request_id]->request_buffer) &&
(tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
- memcpy(tw_dev->srb[request_id]->request_buffer,
- tw_dev->generic_buffer_virt[request_id],
- tw_dev->srb[request_id]->request_bufflen);
+ if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH &&
+ (tw_dev->srb[request_id]->sc_data_direction == DMA_FROM_DEVICE ||
+ tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)) {
+ if (tw_dev->srb[request_id]->use_sg == 0) {
+ memcpy(tw_dev->srb[request_id]->request_buffer,
+ tw_dev->generic_buffer_virt[request_id],
+ tw_dev->srb[request_id]->request_bufflen);
+ }
+ if (tw_dev->srb[request_id]->use_sg == 1) {
+ struct scatterlist *sg = (struct scatterlist
*)tw_dev->srb[request_id]->request_buffer;
+ char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ }
}
} /* End twa_scsiop_execute_scsi_complete() */
drivers/scsi/3w-9xxx.c +24 -6
@@ -59,6 +59,7 @@Fix 'handled=1' ISR usage, remove bogus IRQ check. Remove un-needed eh_abort handler. Add support for embedded firmware error strings. +2.26.02.003 - Correctly handle single sgl's with use_sg=1. */ #include <linux/module.h>
@@ -81,7 +82,7 @@#include "3w-9xxx.h" /* Globals */ -#define TW_DRIVER_VERSION "2.26.02.002" +#define TW_DRIVER_VERSION "2.26.02.003"static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT ];static unsigned int twa_device_extension_count;static int twa_major =-1 ;
@@ -1805,6 +1806,8 @@if (tw_dev->srb[request_id]->request_bufflen <TW_MIN_SGL_LENGTH ) { command_packet->sg_list[0 ].address = tw_dev->generic_buffer_phys[request_id]; command_packet->sg_list[0 ].length =TW_MIN_SGL_LENGTH ; +if (tw_dev->srb[request_id]->sc_data_direction ==DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction ==DMA_BIDIRECTIONAL ) +memcpy (tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen); }else { buffaddr =twa_map_scsi_single_data (tw_dev, request_id);if (buffaddr ==0 )
@@ -1823,6 +1826,12 @@if (tw_dev->srb[request_id]->use_sg >0 ) {if ((tw_dev->srb[request_id]->use_sg ==1 ) && (tw_dev->srb[request_id]->request_bufflen <TW_MIN_SGL_LENGTH )) { +if (tw_dev->srb[request_id]->sc_data_direction ==DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction ==DMA_BIDIRECTIONAL ) { +struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; +char *buf =kmap_atomic (sg->page,KM_IRQ0 ) + sg->offset; +memcpy (tw_dev->generic_buffer_virt[request_id], buf, sg->length); +kunmap_atomic (buf - sg->offset,KM_IRQ0 ); + } command_packet->sg_list[0 ].address = tw_dev->generic_buffer_phys[request_id]; command_packet->sg_list[0 ].length =TW_MIN_SGL_LENGTH ; }else {
@@ -1888,11 +1897,20 @@/* This function completes an execute scsi operation */ static void twa_scsiop_execute_scsi_complete (TW_Device_Extension *tw_dev,int request_id) { -/* Copy the response if too small */ -if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen <TW_MIN_SGL_LENGTH )) { -memcpy (tw_dev->srb[request_id]->request_buffer, - tw_dev->generic_buffer_virt[request_id], - tw_dev->srb[request_id]->request_bufflen); +if (tw_dev->srb[request_id]->request_bufflen <TW_MIN_SGL_LENGTH && + (tw_dev->srb[request_id]->sc_data_direction ==DMA_FROM_DEVICE || + tw_dev->srb[request_id]->sc_data_direction ==DMA_BIDIRECTIONAL )) { +if (tw_dev->srb[request_id]->use_sg ==0 ) { +memcpy (tw_dev->srb[request_id]->request_buffer, + tw_dev->generic_buffer_virt[request_id], + tw_dev->srb[request_id]->request_bufflen); + } +if (tw_dev->srb[request_id]->use_sg ==1 ) { +struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; +char *buf =kmap_atomic (sg->page,KM_IRQ0 ) + sg->offset; +memcpy (buf, tw_dev->generic_buffer_virt[request_id], sg->length); +kunmap_atomic (buf - sg->offset,KM_IRQ0 ); + } } }/* End twa_scsiop_execute_scsi_complete() */