aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 cbf825263f3..0c56095f814 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 7b0f9a3810d..57453ca0970 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 1ace1b9fe53..7602b9b15a0 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 */