diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/dc395x.c | 163 |
1 files changed, 60 insertions, 103 deletions
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 564ea90ed3a0..7b8a3457b696 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c | |||
@@ -979,6 +979,7 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) | |||
979 | static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, | 979 | static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, |
980 | struct ScsiReqBlk *srb) | 980 | struct ScsiReqBlk *srb) |
981 | { | 981 | { |
982 | int nseg; | ||
982 | enum dma_data_direction dir = cmd->sc_data_direction; | 983 | enum dma_data_direction dir = cmd->sc_data_direction; |
983 | dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", | 984 | dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", |
984 | cmd->pid, dcb->target_id, dcb->target_lun); | 985 | cmd->pid, dcb->target_id, dcb->target_lun); |
@@ -1000,27 +1001,30 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, | |||
1000 | srb->scsi_phase = PH_BUS_FREE; /* initial phase */ | 1001 | srb->scsi_phase = PH_BUS_FREE; /* initial phase */ |
1001 | srb->end_message = 0; | 1002 | srb->end_message = 0; |
1002 | 1003 | ||
1003 | if (dir == PCI_DMA_NONE || !cmd->request_buffer) { | 1004 | nseg = scsi_dma_map(cmd); |
1005 | BUG_ON(nseg < 0); | ||
1006 | |||
1007 | if (dir == PCI_DMA_NONE || !nseg) { | ||
1004 | dprintkdbg(DBG_0, | 1008 | dprintkdbg(DBG_0, |
1005 | "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", | 1009 | "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", |
1006 | cmd->bufflen, cmd->request_buffer, | 1010 | cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd), |
1007 | cmd->use_sg, srb->segment_x[0].address); | 1011 | srb->segment_x[0].address); |
1008 | } else if (cmd->use_sg) { | 1012 | } else { |
1009 | int i; | 1013 | int i; |
1010 | u32 reqlen = cmd->request_bufflen; | 1014 | u32 reqlen = scsi_bufflen(cmd); |
1011 | struct scatterlist *sl = (struct scatterlist *) | 1015 | struct scatterlist *sg; |
1012 | cmd->request_buffer; | ||
1013 | struct SGentry *sgp = srb->segment_x; | 1016 | struct SGentry *sgp = srb->segment_x; |
1014 | srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg, | 1017 | |
1015 | dir); | 1018 | srb->sg_count = nseg; |
1019 | |||
1016 | dprintkdbg(DBG_0, | 1020 | dprintkdbg(DBG_0, |
1017 | "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", | 1021 | "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", |
1018 | reqlen, cmd->request_buffer, cmd->use_sg, | 1022 | reqlen, scsi_sglist(cmd), scsi_sg_count(cmd), |
1019 | srb->sg_count); | 1023 | srb->sg_count); |
1020 | 1024 | ||
1021 | for (i = 0; i < srb->sg_count; i++) { | 1025 | scsi_for_each_sg(cmd, sg, srb->sg_count, i) { |
1022 | u32 busaddr = (u32)sg_dma_address(&sl[i]); | 1026 | u32 busaddr = (u32)sg_dma_address(sg); |
1023 | u32 seglen = (u32)sl[i].length; | 1027 | u32 seglen = (u32)sg->length; |
1024 | sgp[i].address = busaddr; | 1028 | sgp[i].address = busaddr; |
1025 | sgp[i].length = seglen; | 1029 | sgp[i].length = seglen; |
1026 | srb->total_xfer_length += seglen; | 1030 | srb->total_xfer_length += seglen; |
@@ -1050,23 +1054,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, | |||
1050 | 1054 | ||
1051 | dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", | 1055 | dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", |
1052 | srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); | 1056 | srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); |
1053 | } else { | ||
1054 | srb->total_xfer_length = cmd->request_bufflen; | ||
1055 | srb->sg_count = 1; | ||
1056 | srb->segment_x[0].address = | ||
1057 | pci_map_single(dcb->acb->dev, cmd->request_buffer, | ||
1058 | srb->total_xfer_length, dir); | ||
1059 | |||
1060 | /* Fixup for WIDE padding - make sure length is even */ | ||
1061 | if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2) | ||
1062 | srb->total_xfer_length++; | ||
1063 | |||
1064 | srb->segment_x[0].length = srb->total_xfer_length; | ||
1065 | |||
1066 | dprintkdbg(DBG_0, | ||
1067 | "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n", | ||
1068 | srb->total_xfer_length, cmd->request_buffer, | ||
1069 | cmd->use_sg, srb->segment_x[0].address); | ||
1070 | } | 1057 | } |
1071 | 1058 | ||
1072 | srb->request_length = srb->total_xfer_length; | 1059 | srb->request_length = srb->total_xfer_length; |
@@ -2128,7 +2115,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, | |||
2128 | /*clear_fifo(acb, "DOP1"); */ | 2115 | /*clear_fifo(acb, "DOP1"); */ |
2129 | /* KG: What is this supposed to be useful for? WIDE padding stuff? */ | 2116 | /* KG: What is this supposed to be useful for? WIDE padding stuff? */ |
2130 | if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC | 2117 | if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC |
2131 | && srb->cmd->request_bufflen % 2) { | 2118 | && scsi_bufflen(srb->cmd) % 2) { |
2132 | d_left_counter = 0; | 2119 | d_left_counter = 0; |
2133 | dprintkl(KERN_INFO, | 2120 | dprintkl(KERN_INFO, |
2134 | "data_out_phase0: Discard 1 byte (0x%02x)\n", | 2121 | "data_out_phase0: Discard 1 byte (0x%02x)\n", |
@@ -2159,7 +2146,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, | |||
2159 | sg_update_list(srb, d_left_counter); | 2146 | sg_update_list(srb, d_left_counter); |
2160 | /* KG: Most ugly hack! Apparently, this works around a chip bug */ | 2147 | /* KG: Most ugly hack! Apparently, this works around a chip bug */ |
2161 | if ((srb->segment_x[srb->sg_index].length == | 2148 | if ((srb->segment_x[srb->sg_index].length == |
2162 | diff && srb->cmd->use_sg) | 2149 | diff && scsi_sg_count(srb->cmd)) |
2163 | || ((oldxferred & ~PAGE_MASK) == | 2150 | || ((oldxferred & ~PAGE_MASK) == |
2164 | (PAGE_SIZE - diff)) | 2151 | (PAGE_SIZE - diff)) |
2165 | ) { | 2152 | ) { |
@@ -2289,19 +2276,15 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, | |||
2289 | unsigned char *virt, *base = NULL; | 2276 | unsigned char *virt, *base = NULL; |
2290 | unsigned long flags = 0; | 2277 | unsigned long flags = 0; |
2291 | size_t len = left_io; | 2278 | size_t len = left_io; |
2279 | size_t offset = srb->request_length - left_io; | ||
2280 | |||
2281 | local_irq_save(flags); | ||
2282 | /* Assumption: it's inside one page as it's at most 4 bytes and | ||
2283 | I just assume it's on a 4-byte boundary */ | ||
2284 | base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd), | ||
2285 | srb->sg_count, &offset, &len); | ||
2286 | virt = base + offset; | ||
2292 | 2287 | ||
2293 | if (srb->cmd->use_sg) { | ||
2294 | size_t offset = srb->request_length - left_io; | ||
2295 | local_irq_save(flags); | ||
2296 | /* Assumption: it's inside one page as it's at most 4 bytes and | ||
2297 | I just assume it's on a 4-byte boundary */ | ||
2298 | base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer, | ||
2299 | srb->sg_count, &offset, &len); | ||
2300 | virt = base + offset; | ||
2301 | } else { | ||
2302 | virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io; | ||
2303 | len = left_io; | ||
2304 | } | ||
2305 | left_io -= len; | 2288 | left_io -= len; |
2306 | 2289 | ||
2307 | while (len) { | 2290 | while (len) { |
@@ -2341,10 +2324,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, | |||
2341 | DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); | 2324 | DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); |
2342 | } | 2325 | } |
2343 | 2326 | ||
2344 | if (srb->cmd->use_sg) { | 2327 | scsi_kunmap_atomic_sg(base); |
2345 | scsi_kunmap_atomic_sg(base); | 2328 | local_irq_restore(flags); |
2346 | local_irq_restore(flags); | ||
2347 | } | ||
2348 | } | 2329 | } |
2349 | /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ | 2330 | /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ |
2350 | /*srb->total_xfer_length = 0; */ | 2331 | /*srb->total_xfer_length = 0; */ |
@@ -2455,7 +2436,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, | |||
2455 | */ | 2436 | */ |
2456 | srb->state |= SRB_DATA_XFER; | 2437 | srb->state |= SRB_DATA_XFER; |
2457 | DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); | 2438 | DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); |
2458 | if (srb->cmd->use_sg) { /* with S/G */ | 2439 | if (scsi_sg_count(srb->cmd)) { /* with S/G */ |
2459 | io_dir |= DMACMD_SG; | 2440 | io_dir |= DMACMD_SG; |
2460 | DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, | 2441 | DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, |
2461 | srb->sg_bus_addr + | 2442 | srb->sg_bus_addr + |
@@ -2513,18 +2494,14 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, | |||
2513 | unsigned char *virt, *base = NULL; | 2494 | unsigned char *virt, *base = NULL; |
2514 | unsigned long flags = 0; | 2495 | unsigned long flags = 0; |
2515 | size_t len = left_io; | 2496 | size_t len = left_io; |
2497 | size_t offset = srb->request_length - left_io; | ||
2498 | |||
2499 | local_irq_save(flags); | ||
2500 | /* Again, max 4 bytes */ | ||
2501 | base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd), | ||
2502 | srb->sg_count, &offset, &len); | ||
2503 | virt = base + offset; | ||
2516 | 2504 | ||
2517 | if (srb->cmd->use_sg) { | ||
2518 | size_t offset = srb->request_length - left_io; | ||
2519 | local_irq_save(flags); | ||
2520 | /* Again, max 4 bytes */ | ||
2521 | base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer, | ||
2522 | srb->sg_count, &offset, &len); | ||
2523 | virt = base + offset; | ||
2524 | } else { | ||
2525 | virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io; | ||
2526 | len = left_io; | ||
2527 | } | ||
2528 | left_io -= len; | 2505 | left_io -= len; |
2529 | 2506 | ||
2530 | while (len--) { | 2507 | while (len--) { |
@@ -2536,10 +2513,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, | |||
2536 | sg_subtract_one(srb); | 2513 | sg_subtract_one(srb); |
2537 | } | 2514 | } |
2538 | 2515 | ||
2539 | if (srb->cmd->use_sg) { | 2516 | scsi_kunmap_atomic_sg(base); |
2540 | scsi_kunmap_atomic_sg(base); | 2517 | local_irq_restore(flags); |
2541 | local_irq_restore(flags); | ||
2542 | } | ||
2543 | } | 2518 | } |
2544 | if (srb->dcb->sync_period & WIDE_SYNC) { | 2519 | if (srb->dcb->sync_period & WIDE_SYNC) { |
2545 | if (ln % 2) { | 2520 | if (ln % 2) { |
@@ -3295,7 +3270,8 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) | |||
3295 | { | 3270 | { |
3296 | struct scsi_cmnd *cmd = srb->cmd; | 3271 | struct scsi_cmnd *cmd = srb->cmd; |
3297 | enum dma_data_direction dir = cmd->sc_data_direction; | 3272 | enum dma_data_direction dir = cmd->sc_data_direction; |
3298 | if (cmd->use_sg && dir != PCI_DMA_NONE) { | 3273 | |
3274 | if (scsi_sg_count(cmd) && dir != PCI_DMA_NONE) { | ||
3299 | /* unmap DC395x SG list */ | 3275 | /* unmap DC395x SG list */ |
3300 | dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", | 3276 | dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", |
3301 | srb->sg_bus_addr, SEGMENTX_LEN); | 3277 | srb->sg_bus_addr, SEGMENTX_LEN); |
@@ -3303,16 +3279,9 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) | |||
3303 | SEGMENTX_LEN, | 3279 | SEGMENTX_LEN, |
3304 | PCI_DMA_TODEVICE); | 3280 | PCI_DMA_TODEVICE); |
3305 | dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", | 3281 | dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", |
3306 | cmd->use_sg, cmd->request_buffer); | 3282 | scsi_sg_count(cmd), scsi_bufflen(cmd)); |
3307 | /* unmap the sg segments */ | 3283 | /* unmap the sg segments */ |
3308 | pci_unmap_sg(acb->dev, | 3284 | scsi_dma_unmap(cmd); |
3309 | (struct scatterlist *)cmd->request_buffer, | ||
3310 | cmd->use_sg, dir); | ||
3311 | } else if (cmd->request_buffer && dir != PCI_DMA_NONE) { | ||
3312 | dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n", | ||
3313 | srb->segment_x[0].address, cmd->request_bufflen); | ||
3314 | pci_unmap_single(acb->dev, srb->segment_x[0].address, | ||
3315 | cmd->request_bufflen, dir); | ||
3316 | } | 3285 | } |
3317 | } | 3286 | } |
3318 | 3287 | ||
@@ -3352,8 +3321,8 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, | |||
3352 | dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid, | 3321 | dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid, |
3353 | srb->cmd->device->id, srb->cmd->device->lun); | 3322 | srb->cmd->device->id, srb->cmd->device->lun); |
3354 | dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", | 3323 | dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", |
3355 | srb, cmd->use_sg, srb->sg_index, srb->sg_count, | 3324 | srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, |
3356 | cmd->request_buffer); | 3325 | scsi_sgtalbe(cmd)); |
3357 | status = srb->target_status; | 3326 | status = srb->target_status; |
3358 | if (srb->flag & AUTO_REQSENSE) { | 3327 | if (srb->flag & AUTO_REQSENSE) { |
3359 | dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); | 3328 | dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); |
@@ -3482,16 +3451,10 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, | |||
3482 | } | 3451 | } |
3483 | } | 3452 | } |
3484 | 3453 | ||
3485 | if (dir != PCI_DMA_NONE) { | 3454 | if (dir != PCI_DMA_NONE && scsi_sg_count(cmd)) |
3486 | if (cmd->use_sg) | 3455 | pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd), |
3487 | pci_dma_sync_sg_for_cpu(acb->dev, | 3456 | scsi_sg_count(cmd), dir); |
3488 | (struct scatterlist *)cmd-> | 3457 | |
3489 | request_buffer, cmd->use_sg, dir); | ||
3490 | else if (cmd->request_buffer) | ||
3491 | pci_dma_sync_single_for_cpu(acb->dev, | ||
3492 | srb->segment_x[0].address, | ||
3493 | cmd->request_bufflen, dir); | ||
3494 | } | ||
3495 | ckc_only = 0; | 3458 | ckc_only = 0; |
3496 | /* Check Error Conditions */ | 3459 | /* Check Error Conditions */ |
3497 | ckc_e: | 3460 | ckc_e: |
@@ -3500,19 +3463,15 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, | |||
3500 | unsigned char *base = NULL; | 3463 | unsigned char *base = NULL; |
3501 | struct ScsiInqData *ptr; | 3464 | struct ScsiInqData *ptr; |
3502 | unsigned long flags = 0; | 3465 | unsigned long flags = 0; |
3466 | struct scatterlist* sg = scsi_sglist(cmd); | ||
3467 | size_t offset = 0, len = sizeof(struct ScsiInqData); | ||
3503 | 3468 | ||
3504 | if (cmd->use_sg) { | 3469 | local_irq_save(flags); |
3505 | struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer; | 3470 | base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len); |
3506 | size_t offset = 0, len = sizeof(struct ScsiInqData); | 3471 | ptr = (struct ScsiInqData *)(base + offset); |
3507 | |||
3508 | local_irq_save(flags); | ||
3509 | base = scsi_kmap_atomic_sg(sg, cmd->use_sg, &offset, &len); | ||
3510 | ptr = (struct ScsiInqData *)(base + offset); | ||
3511 | } else | ||
3512 | ptr = (struct ScsiInqData *)(cmd->request_buffer); | ||
3513 | 3472 | ||
3514 | if (!ckc_only && (cmd->result & RES_DID) == 0 | 3473 | if (!ckc_only && (cmd->result & RES_DID) == 0 |
3515 | && cmd->cmnd[2] == 0 && cmd->request_bufflen >= 8 | 3474 | && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8 |
3516 | && dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2) | 3475 | && dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2) |
3517 | dcb->inquiry7 = ptr->Flags; | 3476 | dcb->inquiry7 = ptr->Flags; |
3518 | 3477 | ||
@@ -3527,14 +3486,12 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, | |||
3527 | } | 3486 | } |
3528 | } | 3487 | } |
3529 | 3488 | ||
3530 | if (cmd->use_sg) { | 3489 | scsi_kunmap_atomic_sg(base); |
3531 | scsi_kunmap_atomic_sg(base); | 3490 | local_irq_restore(flags); |
3532 | local_irq_restore(flags); | ||
3533 | } | ||
3534 | } | 3491 | } |
3535 | 3492 | ||
3536 | /* Here is the info for Doug Gilbert's sg3 ... */ | 3493 | /* Here is the info for Doug Gilbert's sg3 ... */ |
3537 | cmd->resid = srb->total_xfer_length; | 3494 | scsi_set_resid(cmd, srb->total_xfer_length); |
3538 | /* This may be interpreted by sb. or not ... */ | 3495 | /* This may be interpreted by sb. or not ... */ |
3539 | cmd->SCp.this_residual = srb->total_xfer_length; | 3496 | cmd->SCp.this_residual = srb->total_xfer_length; |
3540 | cmd->SCp.buffers_residual = 0; | 3497 | cmd->SCp.buffers_residual = 0; |