diff options
-rw-r--r-- | drivers/scsi/dc395x.c | 217 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 57 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 4 |
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 | ||
980 | static 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 */ |
992 | static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, | 979 | static 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 | */ |
1981 | static void sg_update_list(struct ScsiReqBlk *srb, u32 left) | 1968 | static 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 | */ |
2051 | static void sg_subtract_one(struct ScsiReqBlk *srb) | 2012 | static 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 | |||
2243 | static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, | 2195 | static 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 | } |
2352 | EXPORT_SYMBOL_GPL(scsi_target_unblock); | 2352 | EXPORT_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 | */ | ||
2363 | void *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 | } | ||
2398 | EXPORT_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 | */ | ||
2405 | void scsi_kunmap_atomic_sg(void *virt) | ||
2406 | { | ||
2407 | kunmap_atomic(virt, KM_BIO_SRC_IRQ); | ||
2408 | } | ||
2409 | EXPORT_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 *); | |||
152 | extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); | 152 | extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); |
153 | extern void scsi_finish_command(struct scsi_cmnd *cmd); | 153 | extern void scsi_finish_command(struct scsi_cmnd *cmd); |
154 | 154 | ||
155 | extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, | ||
156 | size_t *offset, size_t *len); | ||
157 | extern void scsi_kunmap_atomic_sg(void *virt); | ||
158 | |||
155 | #endif /* _SCSI_SCSI_CMND_H */ | 159 | #endif /* _SCSI_SCSI_CMND_H */ |