aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2006-04-02 15:57:43 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-14 17:45:27 -0400
commitcdb8c2a6d848deb9eeefffff42974478fbb51b8c (patch)
treefc862e003d35def8bc9d160180ec1b1440679a52
parent4c021dd136c0ad524e6d117296beafad2bf570c0 (diff)
[SCSI] dc395x: dynamically map scatter-gather for PIO
The current dc395x driver uses PIO to transfer up to 4 bytes which do not get transferred by DMA (under unclear circumstances). For this the driver uses page_address() which is broken on highmem. Apart from this the actual calculation of the virtual address is wrong (even without highmem). So, e.g., for reading it reads bytes from the driver to a wrong address and returns wrong data, I guess, for writing it would just output random data to the device. The proper fix, as suggested by many, is to dynamically map data using kmap_atomic(page, KM_BIO_SRC_IRQ) / kunmap_atomic(virt). The reason why it has not been done until now, although I've done some preliminary patches more than a year ago was that nobody interested in fixing this problem was able to reliably reproduce it. Now it changed - with the help from Sebastian Frei (CC'ed) I was able to trigger the PIO path. Thus, I was also able to test and debug it. There are 4 cases when PIO is used in dc395x - data-in / -out with and without scatter-gather. I was able to reproduce and test only data-in with and without SG. So, the data-out path is still untested, but it is also somewhat simpler than the data-in. Fredrik Roubert (also CC'ed) also had PIO triggering on his system, and in his case it was data-out without SG. It would be great if he could test the attached patch on his system, but even if he cannot, I would still request to apply the patch and just wait if anybody cries... Implementation: I put 2 new functions in scsi_lib.c and their declarations in scsi_cmnd.h. I exported them without _GPL, although, I don't feel strongly about that - not many drivers are likely to use them. But there is at least one more - I want to use them in tmscsim.c. Whether these are the right files for the functions and their declarations - not sure either. Actually, they are not scsi-specific, so, might go somewhere around other scattergather magic? They are not platform specific either, and most SG functions are defined under arch/*/... As these issues were discussed previously there were some more routines suggested to manipulate scattergather buffers, I think, some of them were needed around crypto code... So, might be a common place reasonable, like lib/scattergather.c? I am open here. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/dc395x.c217
-rw-r--r--drivers/scsi/scsi_lib.c57
-rw-r--r--include/scsi/scsi_cmnd.h4
3 files changed, 176 insertions, 102 deletions
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index cbf825263f3b..0c56095f8140 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -230,13 +230,12 @@ struct ScsiReqBlk {
230 struct scsi_cmnd *cmd; 230 struct scsi_cmnd *cmd;
231 231
232 struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */ 232 struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */
233 u32 sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ 233 dma_addr_t sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */
234 234
235 u8 sg_count; /* No of HW sg entries for this request */ 235 u8 sg_count; /* No of HW sg entries for this request */
236 u8 sg_index; /* Index of HW sg entry for this request */ 236 u8 sg_index; /* Index of HW sg entry for this request */
237 u32 total_xfer_length; /* Total number of bytes remaining to be transfered */ 237 size_t total_xfer_length; /* Total number of bytes remaining to be transfered */
238 unsigned char *virt_addr; /* Virtual address of current transfer position */ 238 size_t request_length; /* Total number of bytes in this request */
239
240 /* 239 /*
241 * The sense buffer handling function, request_sense, uses 240 * The sense buffer handling function, request_sense, uses
242 * the first hw sg entry (segment_x[0]) and the transfer 241 * the first hw sg entry (segment_x[0]) and the transfer
@@ -246,8 +245,7 @@ struct ScsiReqBlk {
246 * total_xfer_length in xferred. These values are restored in 245 * total_xfer_length in xferred. These values are restored in
247 * pci_unmap_srb_sense. This is the only place xferred is used. 246 * pci_unmap_srb_sense. This is the only place xferred is used.
248 */ 247 */
249 unsigned char *virt_addr_req; /* Saved virtual address of the request buffer */ 248 size_t xferred; /* Saved copy of total_xfer_length */
250 u32 xferred; /* Saved copy of total_xfer_length */
251 249
252 u16 state; 250 u16 state;
253 251
@@ -977,17 +975,6 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
977 } 975 }
978} 976}
979 977
980static inline void pio_trigger(void)
981{
982 static int feedback_requested;
983
984 if (!feedback_requested) {
985 feedback_requested = 1;
986 printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> "
987 "to help improve support for your system.\n", __FILE__);
988 }
989}
990
991/* Prepare SRB for being sent to Device DCB w/ command *cmd */ 978/* Prepare SRB for being sent to Device DCB w/ command *cmd */
992static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, 979static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
993 struct ScsiReqBlk *srb) 980 struct ScsiReqBlk *srb)
@@ -1001,7 +988,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
1001 srb->sg_count = 0; 988 srb->sg_count = 0;
1002 srb->total_xfer_length = 0; 989 srb->total_xfer_length = 0;
1003 srb->sg_bus_addr = 0; 990 srb->sg_bus_addr = 0;
1004 srb->virt_addr = NULL;
1005 srb->sg_index = 0; 991 srb->sg_index = 0;
1006 srb->adapter_status = 0; 992 srb->adapter_status = 0;
1007 srb->target_status = 0; 993 srb->target_status = 0;
@@ -1032,7 +1018,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
1032 reqlen, cmd->request_buffer, cmd->use_sg, 1018 reqlen, cmd->request_buffer, cmd->use_sg,
1033 srb->sg_count); 1019 srb->sg_count);
1034 1020
1035 srb->virt_addr = page_address(sl->page);
1036 for (i = 0; i < srb->sg_count; i++) { 1021 for (i = 0; i < srb->sg_count; i++) {
1037 u32 busaddr = (u32)sg_dma_address(&sl[i]); 1022 u32 busaddr = (u32)sg_dma_address(&sl[i]);
1038 u32 seglen = (u32)sl[i].length; 1023 u32 seglen = (u32)sl[i].length;
@@ -1077,12 +1062,14 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
1077 srb->total_xfer_length++; 1062 srb->total_xfer_length++;
1078 1063
1079 srb->segment_x[0].length = srb->total_xfer_length; 1064 srb->segment_x[0].length = srb->total_xfer_length;
1080 srb->virt_addr = cmd->request_buffer; 1065
1081 dprintkdbg(DBG_0, 1066 dprintkdbg(DBG_0,
1082 "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n", 1067 "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n",
1083 srb->total_xfer_length, cmd->request_buffer, 1068 srb->total_xfer_length, cmd->request_buffer,
1084 cmd->use_sg, srb->segment_x[0].address); 1069 cmd->use_sg, srb->segment_x[0].address);
1085 } 1070 }
1071
1072 srb->request_length = srb->total_xfer_length;
1086} 1073}
1087 1074
1088 1075
@@ -1414,10 +1401,10 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
1414 } 1401 }
1415 srb = find_cmd(cmd, &dcb->srb_going_list); 1402 srb = find_cmd(cmd, &dcb->srb_going_list);
1416 if (srb) { 1403 if (srb) {
1417 dprintkl(KERN_DEBUG, "eh_abort: Command in progress"); 1404 dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n");
1418 /* XXX: Should abort the command here */ 1405 /* XXX: Should abort the command here */
1419 } else { 1406 } else {
1420 dprintkl(KERN_DEBUG, "eh_abort: Command not found"); 1407 dprintkl(KERN_DEBUG, "eh_abort: Command not found\n");
1421 } 1408 }
1422 return FAILED; 1409 return FAILED;
1423} 1410}
@@ -1976,14 +1963,11 @@ static void sg_verify_length(struct ScsiReqBlk *srb)
1976 1963
1977/* 1964/*
1978 * Compute the next Scatter Gather list index and adjust its length 1965 * Compute the next Scatter Gather list index and adjust its length
1979 * and address if necessary; also compute virt_addr 1966 * and address if necessary
1980 */ 1967 */
1981static void sg_update_list(struct ScsiReqBlk *srb, u32 left) 1968static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
1982{ 1969{
1983 u8 idx; 1970 u8 idx;
1984 struct scatterlist *sg;
1985 struct scsi_cmnd *cmd = srb->cmd;
1986 int segment = cmd->use_sg;
1987 u32 xferred = srb->total_xfer_length - left; /* bytes transfered */ 1971 u32 xferred = srb->total_xfer_length - left; /* bytes transfered */
1988 struct SGentry *psge = srb->segment_x + srb->sg_index; 1972 struct SGentry *psge = srb->segment_x + srb->sg_index;
1989 1973
@@ -2016,29 +2000,6 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
2016 psge++; 2000 psge++;
2017 } 2001 }
2018 sg_verify_length(srb); 2002 sg_verify_length(srb);
2019
2020 /* we need the corresponding virtual address */
2021 if (!segment || (srb->flag & AUTO_REQSENSE)) {
2022 srb->virt_addr += xferred;
2023 return;
2024 }
2025
2026 /* We have to walk the scatterlist to find it */
2027 sg = (struct scatterlist *)cmd->request_buffer;
2028 while (segment--) {
2029 unsigned long mask =
2030 ~((unsigned long)sg->length - 1) & PAGE_MASK;
2031 if ((sg_dma_address(sg) & mask) == (psge->address & mask)) {
2032 srb->virt_addr = (page_address(sg->page)
2033 + psge->address -
2034 (psge->address & PAGE_MASK));
2035 return;
2036 }
2037 ++sg;
2038 }
2039
2040 dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n");
2041 srb->virt_addr = NULL;
2042} 2003}
2043 2004
2044 2005
@@ -2050,15 +2011,7 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
2050 */ 2011 */
2051static void sg_subtract_one(struct ScsiReqBlk *srb) 2012static void sg_subtract_one(struct ScsiReqBlk *srb)
2052{ 2013{
2053 srb->total_xfer_length--; 2014 sg_update_list(srb, srb->total_xfer_length - 1);
2054 srb->segment_x[srb->sg_index].length--;
2055 if (srb->total_xfer_length &&
2056 !srb->segment_x[srb->sg_index].length) {
2057 if (debug_enabled(DBG_PIO))
2058 printk(" (next segment)");
2059 srb->sg_index++;
2060 sg_update_list(srb, srb->total_xfer_length);
2061 }
2062} 2015}
2063 2016
2064 2017
@@ -2118,7 +2071,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
2118 * If we need more data, the DMA SG list will be freshly set up, anyway 2071 * If we need more data, the DMA SG list will be freshly set up, anyway
2119 */ 2072 */
2120 dprintkdbg(DBG_PIO, "data_out_phase0: " 2073 dprintkdbg(DBG_PIO, "data_out_phase0: "
2121 "DMA{fifcnt=0x%02x fifostat=0x%02x} " 2074 "DMA{fifocnt=0x%02x fifostat=0x%02x} "
2122 "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", 2075 "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n",
2123 DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), 2076 DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
2124 DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), 2077 DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
@@ -2239,12 +2192,11 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
2239 data_io_transfer(acb, srb, XFERDATAOUT); 2192 data_io_transfer(acb, srb, XFERDATAOUT);
2240} 2193}
2241 2194
2242
2243static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 2195static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
2244 u16 *pscsi_status) 2196 u16 *pscsi_status)
2245{ 2197{
2246 u16 scsi_status = *pscsi_status; 2198 u16 scsi_status = *pscsi_status;
2247 u32 d_left_counter = 0; 2199
2248 dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", 2200 dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
2249 srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); 2201 srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
2250 2202
@@ -2262,6 +2214,9 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
2262 * seem to be a bad idea, actually. 2214 * seem to be a bad idea, actually.
2263 */ 2215 */
2264 if (!(srb->state & SRB_XFERPAD)) { 2216 if (!(srb->state & SRB_XFERPAD)) {
2217 u32 d_left_counter;
2218 unsigned int sc, fc;
2219
2265 if (scsi_status & PARITYERROR) { 2220 if (scsi_status & PARITYERROR) {
2266 dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " 2221 dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
2267 "Parity Error\n", srb->cmd->pid); 2222 "Parity Error\n", srb->cmd->pid);
@@ -2298,18 +2253,19 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
2298 DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); 2253 DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
2299 } 2254 }
2300 /* Now: Check remainig data: The SCSI counters should tell us ... */ 2255 /* Now: Check remainig data: The SCSI counters should tell us ... */
2301 d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER) 2256 sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
2302 + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f) 2257 fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
2258 d_left_counter = sc + ((fc & 0x1f)
2303 << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : 2259 << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
2304 0)); 2260 0));
2305 dprintkdbg(DBG_KG, "data_in_phase0: " 2261 dprintkdbg(DBG_KG, "data_in_phase0: "
2306 "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " 2262 "SCSI{fifocnt=0x%02x%s ctr=0x%08x} "
2307 "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " 2263 "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} "
2308 "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", 2264 "Remain{totxfer=%i scsi_fifo+ctr=%i}\n",
2309 DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), 2265 fc,
2310 (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", 2266 (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
2311 DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), 2267 sc,
2312 DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), 2268 fc,
2313 DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), 2269 DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
2314 DC395x_read32(acb, TRM_S1040_DMA_CXCNT), 2270 DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
2315 srb->total_xfer_length, d_left_counter); 2271 srb->total_xfer_length, d_left_counter);
@@ -2317,40 +2273,79 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
2317 /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ 2273 /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */
2318 if (d_left_counter 2274 if (d_left_counter
2319 && srb->total_xfer_length <= DC395x_LASTPIO) { 2275 && srb->total_xfer_length <= DC395x_LASTPIO) {
2276 size_t left_io = srb->total_xfer_length;
2277
2320 /*u32 addr = (srb->segment_x[srb->sg_index].address); */ 2278 /*u32 addr = (srb->segment_x[srb->sg_index].address); */
2321 /*sg_update_list (srb, d_left_counter); */ 2279 /*sg_update_list (srb, d_left_counter); */
2322 dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to " 2280 dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) "
2323 "%p for remaining %i bytes:", 2281 "for remaining %i bytes:",
2324 DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f, 2282 fc & 0x1f,
2325 (srb->dcb->sync_period & WIDE_SYNC) ? 2283 (srb->dcb->sync_period & WIDE_SYNC) ?
2326 "words" : "bytes", 2284 "words" : "bytes",
2327 srb->virt_addr,
2328 srb->total_xfer_length); 2285 srb->total_xfer_length);
2329 if (srb->dcb->sync_period & WIDE_SYNC) 2286 if (srb->dcb->sync_period & WIDE_SYNC)
2330 DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 2287 DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
2331 CFG2_WIDEFIFO); 2288 CFG2_WIDEFIFO);
2332 while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) { 2289 while (left_io) {
2333 u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 2290 unsigned char *virt, *base = NULL;
2334 pio_trigger(); 2291 unsigned long flags = 0;
2335 *(srb->virt_addr)++ = byte; 2292 size_t len = left_io;
2336 if (debug_enabled(DBG_PIO)) 2293
2337 printk(" %02x", byte); 2294 if (srb->cmd->use_sg) {
2338 d_left_counter--; 2295 size_t offset = srb->request_length - left_io;
2339 sg_subtract_one(srb); 2296 local_irq_save(flags);
2340 } 2297 /* Assumption: it's inside one page as it's at most 4 bytes and
2341 if (srb->dcb->sync_period & WIDE_SYNC) { 2298 I just assume it's on a 4-byte boundary */
2342#if 1 2299 base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
2343 /* Read the last byte ... */ 2300 srb->sg_count, &offset, &len);
2344 if (srb->total_xfer_length > 0) { 2301 virt = base + offset;
2345 u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 2302 } else {
2346 pio_trigger(); 2303 virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
2347 *(srb->virt_addr)++ = byte; 2304 len = left_io;
2348 srb->total_xfer_length--; 2305 }
2306 left_io -= len;
2307
2308 while (len) {
2309 u8 byte;
2310 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
2311 *virt++ = byte;
2312
2349 if (debug_enabled(DBG_PIO)) 2313 if (debug_enabled(DBG_PIO))
2350 printk(" %02x", byte); 2314 printk(" %02x", byte);
2315
2316 d_left_counter--;
2317 sg_subtract_one(srb);
2318
2319 len--;
2320
2321 fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
2322
2323 if (fc == 0x40) {
2324 left_io = 0;
2325 break;
2326 }
2327 }
2328
2329 WARN_ON((fc != 0x40) == !d_left_counter);
2330
2331 if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) {
2332 /* Read the last byte ... */
2333 if (srb->total_xfer_length > 0) {
2334 u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
2335
2336 *virt++ = byte;
2337 srb->total_xfer_length--;
2338 if (debug_enabled(DBG_PIO))
2339 printk(" %02x", byte);
2340 }
2341
2342 DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
2343 }
2344
2345 if (srb->cmd->use_sg) {
2346 scsi_kunmap_atomic_sg(base);
2347 local_irq_restore(flags);
2351 } 2348 }
2352#endif
2353 DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
2354 } 2349 }
2355 /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ 2350 /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
2356 /*srb->total_xfer_length = 0; */ 2351 /*srb->total_xfer_length = 0; */
@@ -2509,22 +2504,43 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
2509 SCMD_FIFO_IN); 2504 SCMD_FIFO_IN);
2510 } else { /* write */ 2505 } else { /* write */
2511 int ln = srb->total_xfer_length; 2506 int ln = srb->total_xfer_length;
2507 size_t left_io = srb->total_xfer_length;
2508
2512 if (srb->dcb->sync_period & WIDE_SYNC) 2509 if (srb->dcb->sync_period & WIDE_SYNC)
2513 DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 2510 DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
2514 CFG2_WIDEFIFO); 2511 CFG2_WIDEFIFO);
2515 dprintkdbg(DBG_PIO,
2516 "data_io_transfer: PIO %i bytes from %p:",
2517 srb->total_xfer_length, srb->virt_addr);
2518 2512
2519 while (srb->total_xfer_length) { 2513 while (left_io) {
2520 if (debug_enabled(DBG_PIO)) 2514 unsigned char *virt, *base = NULL;
2521 printk(" %02x", (unsigned char) *(srb->virt_addr)); 2515 unsigned long flags = 0;
2516 size_t len = left_io;
2517
2518 if (srb->cmd->use_sg) {
2519 size_t offset = srb->request_length - left_io;
2520 local_irq_save(flags);
2521 /* Again, max 4 bytes */
2522 base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
2523 srb->sg_count, &offset, &len);
2524 virt = base + offset;
2525 } else {
2526 virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
2527 len = left_io;
2528 }
2529 left_io -= len;
2530
2531 while (len--) {
2532 if (debug_enabled(DBG_PIO))
2533 printk(" %02x", *virt);
2522 2534
2523 pio_trigger(); 2535 DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++);
2524 DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
2525 *(srb->virt_addr)++);
2526 2536
2527 sg_subtract_one(srb); 2537 sg_subtract_one(srb);
2538 }
2539
2540 if (srb->cmd->use_sg) {
2541 scsi_kunmap_atomic_sg(base);
2542 local_irq_restore(flags);
2543 }
2528 } 2544 }
2529 if (srb->dcb->sync_period & WIDE_SYNC) { 2545 if (srb->dcb->sync_period & WIDE_SYNC) {
2530 if (ln % 2) { 2546 if (ln % 2) {
@@ -3319,7 +3335,6 @@ static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
3319 srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address; 3335 srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address;
3320 srb->segment_x[0].length = 3336 srb->segment_x[0].length =
3321 srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length; 3337 srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length;
3322 srb->virt_addr = srb->virt_addr_req;
3323} 3338}
3324 3339
3325 3340
@@ -3713,8 +3728,6 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
3713 srb->xferred = srb->total_xfer_length; 3728 srb->xferred = srb->total_xfer_length;
3714 /* srb->segment_x : a one entry of S/G list table */ 3729 /* srb->segment_x : a one entry of S/G list table */
3715 srb->total_xfer_length = sizeof(cmd->sense_buffer); 3730 srb->total_xfer_length = sizeof(cmd->sense_buffer);
3716 srb->virt_addr_req = srb->virt_addr;
3717 srb->virt_addr = cmd->sense_buffer;
3718 srb->segment_x[0].length = sizeof(cmd->sense_buffer); 3731 srb->segment_x[0].length = sizeof(cmd->sense_buffer);
3719 /* Map sense buffer */ 3732 /* Map sense buffer */
3720 srb->segment_x[0].address = 3733 srb->segment_x[0].address =
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7b0f9a3810d2..57453ca09700 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2350,3 +2350,60 @@ scsi_target_unblock(struct device *dev)
2350 device_for_each_child(dev, NULL, target_unblock); 2350 device_for_each_child(dev, NULL, target_unblock);
2351} 2351}
2352EXPORT_SYMBOL_GPL(scsi_target_unblock); 2352EXPORT_SYMBOL_GPL(scsi_target_unblock);
2353
2354/**
2355 * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
2356 * @sg: scatter-gather list
2357 * @sg_count: number of segments in sg
2358 * @offset: offset in bytes into sg, on return offset into the mapped area
2359 * @len: bytes to map, on return number of bytes mapped
2360 *
2361 * Returns virtual address of the start of the mapped page
2362 */
2363void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
2364 size_t *offset, size_t *len)
2365{
2366 int i;
2367 size_t sg_len = 0, len_complete = 0;
2368 struct page *page;
2369
2370 for (i = 0; i < sg_count; i++) {
2371 len_complete = sg_len; /* Complete sg-entries */
2372 sg_len += sg[i].length;
2373 if (sg_len > *offset)
2374 break;
2375 }
2376
2377 if (unlikely(i == sg_count)) {
2378 printk(KERN_ERR "%s: Bytes in sg: %u, requested offset %u, elements %d\n",
2379 __FUNCTION__, sg_len, *offset, sg_count);
2380 WARN_ON(1);
2381 return NULL;
2382 }
2383
2384 /* Offset starting from the beginning of first page in this sg-entry */
2385 *offset = *offset - len_complete + sg[i].offset;
2386
2387 /* Assumption: contiguous pages can be accessed as "page + i" */
2388 page = nth_page(sg[i].page, (*offset >> PAGE_SHIFT));
2389 *offset &= ~PAGE_MASK;
2390
2391 /* Bytes in this sg-entry from *offset to the end of the page */
2392 sg_len = PAGE_SIZE - *offset;
2393 if (*len > sg_len)
2394 *len = sg_len;
2395
2396 return kmap_atomic(page, KM_BIO_SRC_IRQ);
2397}
2398EXPORT_SYMBOL(scsi_kmap_atomic_sg);
2399
2400/**
2401 * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
2402 * mapped with scsi_kmap_atomic_sg
2403 * @virt: virtual address to be unmapped
2404 */
2405void scsi_kunmap_atomic_sg(void *virt)
2406{
2407 kunmap_atomic(virt, KM_BIO_SRC_IRQ);
2408}
2409EXPORT_SYMBOL(scsi_kunmap_atomic_sg);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 1ace1b9fe537..7602b9b15a03 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -152,4 +152,8 @@ extern void scsi_put_command(struct scsi_cmnd *);
152extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); 152extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
153extern void scsi_finish_command(struct scsi_cmnd *cmd); 153extern void scsi_finish_command(struct scsi_cmnd *cmd);
154 154
155extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
156 size_t *offset, size_t *len);
157extern void scsi_kunmap_atomic_sg(void *virt);
158
155#endif /* _SCSI_SCSI_CMND_H */ 159#endif /* _SCSI_SCSI_CMND_H */