Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac_scsi: Fix pseudo DMA implementation

Fix various issues: Comments about bus errors are incorrect. The
PDMA asm must return the size of the memory access that faulted so the
transfer count can be adjusted accordingly. A phase change may cause a
bus error but should not be treated as failure. A bus error does not
always imply a phase change and generally the transfer may continue.
Scatter/gather doesn't seem to work with PDMA due to overruns. This is
a pity because peak throughput seems to double with SG_ALL.
Tested on a Mac LC III and a PowerBook 520.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Finn Thain and committed by
Martin K. Petersen
3a0f64bf ded155b5

+110 -86
+2
drivers/scsi/NCR5380.h
··· 292 292 static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *); 293 293 static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); 294 294 static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); 295 + static int NCR5380_poll_politely(struct Scsi_Host *, int, int, int, int); 296 + static int NCR5380_poll_politely2(struct Scsi_Host *, int, int, int, int, int, int, int); 295 297 296 298 #endif /* __KERNEL__ */ 297 299 #endif /* NCR5380_H */
+108 -86
drivers/scsi/mac_scsi.c
··· 28 28 29 29 /* Definitions for the core NCR5380 driver. */ 30 30 31 - #define NCR5380_implementation_fields unsigned char *pdma_base 31 + #define NCR5380_implementation_fields unsigned char *pdma_base; \ 32 + int pdma_residual 32 33 33 34 #define NCR5380_read(reg) macscsi_read(instance, reg) 34 35 #define NCR5380_write(reg, value) macscsi_write(instance, reg, value) ··· 38 37 macscsi_dma_xfer_len(instance, cmd) 39 38 #define NCR5380_dma_recv_setup macscsi_pread 40 39 #define NCR5380_dma_send_setup macscsi_pwrite 41 - #define NCR5380_dma_residual(instance) (0) 40 + #define NCR5380_dma_residual(instance) (hostdata->pdma_residual) 42 41 43 42 #define NCR5380_intr macscsi_intr 44 43 #define NCR5380_queue_command macscsi_queue_command ··· 105 104 __setup("mac5380=", mac_scsi_setup); 106 105 #endif /* !MODULE */ 107 106 108 - /* 109 - Pseudo-DMA: (Ove Edlund) 110 - The code attempts to catch bus errors that occur if one for example 111 - "trips over the cable". 112 - XXX: Since bus errors in the PDMA routines never happen on my 113 - computer, the bus error code is untested. 114 - If the code works as intended, a bus error results in Pseudo-DMA 115 - being disabled, meaning that the driver switches to slow handshake. 116 - If bus errors are NOT extremely rare, this has to be changed. 117 - */ 107 + /* Pseudo DMA asm originally by Ove Edlund */ 118 108 119 - #define CP_IO_TO_MEM(s,d,len) \ 109 + #define CP_IO_TO_MEM(s,d,n) \ 120 110 __asm__ __volatile__ \ 121 111 (" cmp.w #4,%2\n" \ 122 112 " bls 8f\n" \ ··· 144 152 " 9: \n" \ 145 153 ".section .fixup,\"ax\"\n" \ 146 154 " .even\n" \ 147 - "90: moveq.l #1, %2\n" \ 155 + "91: moveq.l #1, %2\n" \ 156 + " jra 9b\n" \ 157 + "94: moveq.l #4, %2\n" \ 148 158 " jra 9b\n" \ 149 159 ".previous\n" \ 150 160 ".section __ex_table,\"a\"\n" \ 151 161 " .align 4\n" \ 152 - " .long 1b,90b\n" \ 153 - " .long 3b,90b\n" \ 154 - " .long 31b,90b\n" \ 155 - " .long 32b,90b\n" \ 156 - " .long 33b,90b\n" \ 157 - " .long 34b,90b\n" \ 158 - " .long 35b,90b\n" \ 159 - " .long 36b,90b\n" \ 160 - " .long 37b,90b\n" \ 161 - " .long 5b,90b\n" \ 162 - " .long 7b,90b\n" \ 162 + " .long 1b,91b\n" \ 163 + " .long 3b,94b\n" \ 164 + " .long 31b,94b\n" \ 165 + " .long 32b,94b\n" \ 166 + " .long 33b,94b\n" \ 167 + " .long 34b,94b\n" \ 168 + " .long 35b,94b\n" \ 169 + " .long 36b,94b\n" \ 170 + " .long 37b,94b\n" \ 171 + " .long 5b,94b\n" \ 172 + " .long 7b,91b\n" \ 163 173 ".previous" \ 164 - : "=a"(s), "=a"(d), "=d"(len) \ 165 - : "0"(s), "1"(d), "2"(len) \ 174 + : "=a"(s), "=a"(d), "=d"(n) \ 175 + : "0"(s), "1"(d), "2"(n) \ 166 176 : "d0") 167 177 168 178 static int macscsi_pread(struct Scsi_Host *instance, 169 179 unsigned char *dst, int len) 170 180 { 171 181 struct NCR5380_hostdata *hostdata = shost_priv(instance); 172 - unsigned char *d; 173 - unsigned char *s; 182 + unsigned char *s = hostdata->pdma_base + (INPUT_DATA_REG << 4); 183 + unsigned char *d = dst; 184 + int n = len; 185 + int transferred; 174 186 175 - s = hostdata->pdma_base + (INPUT_DATA_REG << 4); 176 - d = dst; 187 + while (!NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, 188 + BASR_DRQ | BASR_PHASE_MATCH, 189 + BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { 190 + CP_IO_TO_MEM(s, d, n); 177 191 178 - /* These conditions are derived from MacOS */ 192 + transferred = d - dst - n; 193 + hostdata->pdma_residual = len - transferred; 179 194 180 - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && 181 - !(NCR5380_read(STATUS_REG) & SR_REQ)) 182 - ; 195 + /* No bus error. */ 196 + if (n == 0) 197 + return 0; 183 198 184 - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && 185 - (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { 186 - pr_err("Error in macscsi_pread\n"); 187 - return -1; 199 + /* Target changed phase early? */ 200 + if (NCR5380_poll_politely2(instance, STATUS_REG, SR_REQ, SR_REQ, 201 + BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0) 202 + scmd_printk(KERN_ERR, hostdata->connected, 203 + "%s: !REQ and !ACK\n", __func__); 204 + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) 205 + return 0; 206 + 207 + dsprintk(NDEBUG_PSEUDO_DMA, instance, 208 + "%s: bus error (%d/%d)\n", __func__, transferred, len); 209 + NCR5380_dprint(NDEBUG_PSEUDO_DMA, instance); 210 + d = dst + transferred; 211 + n = len - transferred; 188 212 } 189 213 190 - CP_IO_TO_MEM(s, d, len); 191 - 192 - if (len != 0) { 193 - pr_notice("Bus error in macscsi_pread\n"); 194 - return -1; 195 - } 196 - 197 - return 0; 214 + scmd_printk(KERN_ERR, hostdata->connected, 215 + "%s: phase mismatch or !DRQ\n", __func__); 216 + NCR5380_dprint(NDEBUG_PSEUDO_DMA, instance); 217 + return -1; 198 218 } 199 219 200 220 201 - #define CP_MEM_TO_IO(s,d,len) \ 221 + #define CP_MEM_TO_IO(s,d,n) \ 202 222 __asm__ __volatile__ \ 203 223 (" cmp.w #4,%2\n" \ 204 224 " bls 8f\n" \ ··· 247 243 " 9: \n" \ 248 244 ".section .fixup,\"ax\"\n" \ 249 245 " .even\n" \ 250 - "90: moveq.l #1, %2\n" \ 246 + "91: moveq.l #1, %2\n" \ 247 + " jra 9b\n" \ 248 + "94: moveq.l #4, %2\n" \ 251 249 " jra 9b\n" \ 252 250 ".previous\n" \ 253 251 ".section __ex_table,\"a\"\n" \ 254 252 " .align 4\n" \ 255 - " .long 1b,90b\n" \ 256 - " .long 3b,90b\n" \ 257 - " .long 31b,90b\n" \ 258 - " .long 32b,90b\n" \ 259 - " .long 33b,90b\n" \ 260 - " .long 34b,90b\n" \ 261 - " .long 35b,90b\n" \ 262 - " .long 36b,90b\n" \ 263 - " .long 37b,90b\n" \ 264 - " .long 5b,90b\n" \ 265 - " .long 7b,90b\n" \ 253 + " .long 1b,91b\n" \ 254 + " .long 3b,94b\n" \ 255 + " .long 31b,94b\n" \ 256 + " .long 32b,94b\n" \ 257 + " .long 33b,94b\n" \ 258 + " .long 34b,94b\n" \ 259 + " .long 35b,94b\n" \ 260 + " .long 36b,94b\n" \ 261 + " .long 37b,94b\n" \ 262 + " .long 5b,94b\n" \ 263 + " .long 7b,91b\n" \ 266 264 ".previous" \ 267 - : "=a"(s), "=a"(d), "=d"(len) \ 268 - : "0"(s), "1"(d), "2"(len) \ 265 + : "=a"(s), "=a"(d), "=d"(n) \ 266 + : "0"(s), "1"(d), "2"(n) \ 269 267 : "d0") 270 268 271 269 static int macscsi_pwrite(struct Scsi_Host *instance, 272 270 unsigned char *src, int len) 273 271 { 274 272 struct NCR5380_hostdata *hostdata = shost_priv(instance); 275 - unsigned char *s; 276 - unsigned char *d; 273 + unsigned char *s = src; 274 + unsigned char *d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4); 275 + int n = len; 276 + int transferred; 277 277 278 - s = src; 279 - d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4); 278 + while (!NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, 279 + BASR_DRQ | BASR_PHASE_MATCH, 280 + BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { 281 + CP_MEM_TO_IO(s, d, n); 280 282 281 - /* These conditions are derived from MacOS */ 283 + transferred = s - src - n; 284 + hostdata->pdma_residual = len - transferred; 282 285 283 - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && 284 - (!(NCR5380_read(STATUS_REG) & SR_REQ) || 285 - (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) 286 - ; 286 + /* Target changed phase early? */ 287 + if (NCR5380_poll_politely2(instance, STATUS_REG, SR_REQ, SR_REQ, 288 + BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0) 289 + scmd_printk(KERN_ERR, hostdata->connected, 290 + "%s: !REQ and !ACK\n", __func__); 291 + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) 292 + return 0; 287 293 288 - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) { 289 - pr_err("Error in macscsi_pwrite\n"); 290 - return -1; 294 + /* No bus error. */ 295 + if (n == 0) { 296 + if (NCR5380_poll_politely(instance, TARGET_COMMAND_REG, 297 + TCR_LAST_BYTE_SENT, 298 + TCR_LAST_BYTE_SENT, HZ / 64) < 0) 299 + scmd_printk(KERN_ERR, hostdata->connected, 300 + "%s: Last Byte Sent timeout\n", __func__); 301 + return 0; 302 + } 303 + 304 + dsprintk(NDEBUG_PSEUDO_DMA, instance, 305 + "%s: bus error (%d/%d)\n", __func__, transferred, len); 306 + NCR5380_dprint(NDEBUG_PSEUDO_DMA, instance); 307 + s = src + transferred; 308 + n = len - transferred; 291 309 } 292 310 293 - CP_MEM_TO_IO(s, d, len); 311 + scmd_printk(KERN_ERR, hostdata->connected, 312 + "%s: phase mismatch or !DRQ\n", __func__); 313 + NCR5380_dprint(NDEBUG_PSEUDO_DMA, instance); 294 314 295 - if (len != 0) { 296 - pr_notice("Bus error in macscsi_pwrite\n"); 297 - return -1; 298 - } 299 - 300 - return 0; 315 + return -1; 301 316 } 302 317 303 318 static int macscsi_dma_xfer_len(struct Scsi_Host *instance, ··· 324 301 { 325 302 struct NCR5380_hostdata *hostdata = shost_priv(instance); 326 303 327 - if (hostdata->flags & FLAG_NO_PSEUDO_DMA) 304 + if (hostdata->flags & FLAG_NO_PSEUDO_DMA || 305 + cmd->SCp.this_residual < 16) 328 306 return 0; 329 307 330 - return cmd->transfersize; 308 + return cmd->SCp.this_residual; 331 309 } 332 310 333 311 #include "NCR5380.c" ··· 346 322 .eh_bus_reset_handler = macscsi_bus_reset, 347 323 .can_queue = 16, 348 324 .this_id = 7, 349 - .sg_tablesize = SG_ALL, 325 + .sg_tablesize = 1, 350 326 .cmd_per_lun = 2, 351 327 .use_clustering = DISABLE_CLUSTERING, 352 328 .cmd_size = NCR5380_CMD_SIZE, ··· 382 358 mac_scsi_template.sg_tablesize = setup_sg_tablesize; 383 359 if (setup_hostid >= 0) 384 360 mac_scsi_template.this_id = setup_hostid & 7; 385 - if (setup_use_pdma < 0) 386 - setup_use_pdma = 0; 387 361 388 362 instance = scsi_host_alloc(&mac_scsi_template, 389 363 sizeof(struct NCR5380_hostdata));