1 /* 2 * Generic Macintosh NCR5380 driver 3 * 4 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov> 5 * 6 * derived in part from: 7 */ 8 /* 9 * Generic Generic NCR5380 driver 10 * 11 * Copyright 1995, Russell King 12 */ 13 14 #include <linux/types.h> 15 #include <linux/module.h> 16 #include <linux/ioport.h> 17 #include <linux/init.h> 18 #include <linux/blkdev.h> 19 #include <linux/interrupt.h> 20 #include <linux/platform_device.h> 21 22 #include <asm/hwtest.h> 23 #include <asm/io.h> 24 #include <asm/macints.h> 25 #include <asm/setup.h> 26 27 #include <scsi/scsi_host.h> 28 29 /* Definitions for the core NCR5380 driver. */ 30 31 #define NCR5380_implementation_fields unsigned char *pdma_base 32 33 #define NCR5380_read(reg) macscsi_read(instance, reg) 34 #define NCR5380_write(reg, value) macscsi_write(instance, reg, value) 35 36 #define NCR5380_dma_xfer_len(instance, cmd, phase) \ 37 macscsi_dma_xfer_len(instance, cmd) 38 #define NCR5380_dma_recv_setup macscsi_pread 39 #define NCR5380_dma_send_setup macscsi_pwrite 40 #define NCR5380_dma_residual(instance) (0) 41 42 #define NCR5380_intr macscsi_intr 43 #define NCR5380_queue_command macscsi_queue_command 44 #define NCR5380_abort macscsi_abort 45 #define NCR5380_bus_reset macscsi_bus_reset 46 #define NCR5380_info macscsi_info 47 48 #include "NCR5380.h" 49 50 static int setup_can_queue = -1; 51 module_param(setup_can_queue, int, 0); 52 static int setup_cmd_per_lun = -1; 53 module_param(setup_cmd_per_lun, int, 0); 54 static int setup_sg_tablesize = -1; 55 module_param(setup_sg_tablesize, int, 0); 56 static int setup_use_pdma = -1; 57 module_param(setup_use_pdma, int, 0); 58 static int setup_hostid = -1; 59 module_param(setup_hostid, int, 0); 60 static int setup_toshiba_delay = -1; 61 module_param(setup_toshiba_delay, int, 0); 62 63 /* 64 * NCR 5380 register access functions 65 */ 66 67 static inline char macscsi_read(struct Scsi_Host *instance, int reg) 68 { 69 return in_8(instance->base + (reg << 4)); 70 } 71 72 static inline void macscsi_write(struct Scsi_Host *instance, int reg, int value) 73 { 74 out_8(instance->base + (reg << 4), value); 75 } 76 77 #ifndef MODULE 78 static int __init mac_scsi_setup(char *str) 79 { 80 int ints[8]; 81 82 (void)get_options(str, ARRAY_SIZE(ints), ints); 83 84 if (ints[0] < 1) { 85 pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n"); 86 return 0; 87 } 88 if (ints[0] >= 1) 89 setup_can_queue = ints[1]; 90 if (ints[0] >= 2) 91 setup_cmd_per_lun = ints[2]; 92 if (ints[0] >= 3) 93 setup_sg_tablesize = ints[3]; 94 if (ints[0] >= 4) 95 setup_hostid = ints[4]; 96 /* ints[5] (use_tagged_queuing) is ignored */ 97 if (ints[0] >= 6) 98 setup_use_pdma = ints[6]; 99 if (ints[0] >= 7) 100 setup_toshiba_delay = ints[7]; 101 return 1; 102 } 103 104 __setup("mac5380=", mac_scsi_setup); 105 #endif /* !MODULE */ 106 107 /* 108 Pseudo-DMA: (Ove Edlund) 109 The code attempts to catch bus errors that occur if one for example 110 "trips over the cable". 111 XXX: Since bus errors in the PDMA routines never happen on my 112 computer, the bus error code is untested. 113 If the code works as intended, a bus error results in Pseudo-DMA 114 being disabled, meaning that the driver switches to slow handshake. 115 If bus errors are NOT extremely rare, this has to be changed. 116 */ 117 118 #define CP_IO_TO_MEM(s,d,len) \ 119 __asm__ __volatile__ \ 120 (" cmp.w #4,%2\n" \ 121 " bls 8f\n" \ 122 " move.w %1,%%d0\n" \ 123 " neg.b %%d0\n" \ 124 " and.w #3,%%d0\n" \ 125 " sub.w %%d0,%2\n" \ 126 " bra 2f\n" \ 127 " 1: move.b (%0),(%1)+\n" \ 128 " 2: dbf %%d0,1b\n" \ 129 " move.w %2,%%d0\n" \ 130 " lsr.w #5,%%d0\n" \ 131 " bra 4f\n" \ 132 " 3: move.l (%0),(%1)+\n" \ 133 "31: move.l (%0),(%1)+\n" \ 134 "32: move.l (%0),(%1)+\n" \ 135 "33: move.l (%0),(%1)+\n" \ 136 "34: move.l (%0),(%1)+\n" \ 137 "35: move.l (%0),(%1)+\n" \ 138 "36: move.l (%0),(%1)+\n" \ 139 "37: move.l (%0),(%1)+\n" \ 140 " 4: dbf %%d0,3b\n" \ 141 " move.w %2,%%d0\n" \ 142 " lsr.w #2,%%d0\n" \ 143 " and.w #7,%%d0\n" \ 144 " bra 6f\n" \ 145 " 5: move.l (%0),(%1)+\n" \ 146 " 6: dbf %%d0,5b\n" \ 147 " and.w #3,%2\n" \ 148 " bra 8f\n" \ 149 " 7: move.b (%0),(%1)+\n" \ 150 " 8: dbf %2,7b\n" \ 151 " moveq.l #0, %2\n" \ 152 " 9: \n" \ 153 ".section .fixup,\"ax\"\n" \ 154 " .even\n" \ 155 "90: moveq.l #1, %2\n" \ 156 " jra 9b\n" \ 157 ".previous\n" \ 158 ".section __ex_table,\"a\"\n" \ 159 " .align 4\n" \ 160 " .long 1b,90b\n" \ 161 " .long 3b,90b\n" \ 162 " .long 31b,90b\n" \ 163 " .long 32b,90b\n" \ 164 " .long 33b,90b\n" \ 165 " .long 34b,90b\n" \ 166 " .long 35b,90b\n" \ 167 " .long 36b,90b\n" \ 168 " .long 37b,90b\n" \ 169 " .long 5b,90b\n" \ 170 " .long 7b,90b\n" \ 171 ".previous" \ 172 : "=a"(s), "=a"(d), "=d"(len) \ 173 : "0"(s), "1"(d), "2"(len) \ 174 : "d0") 175 176 static int macscsi_pread(struct Scsi_Host *instance, 177 unsigned char *dst, int len) 178 { 179 struct NCR5380_hostdata *hostdata = shost_priv(instance); 180 unsigned char *d; 181 unsigned char *s; 182 183 s = hostdata->pdma_base + (INPUT_DATA_REG << 4); 184 d = dst; 185 186 /* These conditions are derived from MacOS */ 187 188 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && 189 !(NCR5380_read(STATUS_REG) & SR_REQ)) 190 ; 191 192 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && 193 (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { 194 pr_err("Error in macscsi_pread\n"); 195 return -1; 196 } 197 198 CP_IO_TO_MEM(s, d, len); 199 200 if (len != 0) { 201 pr_notice("Bus error in macscsi_pread\n"); 202 return -1; 203 } 204 205 return 0; 206 } 207 208 209 #define CP_MEM_TO_IO(s,d,len) \ 210 __asm__ __volatile__ \ 211 (" cmp.w #4,%2\n" \ 212 " bls 8f\n" \ 213 " move.w %0,%%d0\n" \ 214 " neg.b %%d0\n" \ 215 " and.w #3,%%d0\n" \ 216 " sub.w %%d0,%2\n" \ 217 " bra 2f\n" \ 218 " 1: move.b (%0)+,(%1)\n" \ 219 " 2: dbf %%d0,1b\n" \ 220 " move.w %2,%%d0\n" \ 221 " lsr.w #5,%%d0\n" \ 222 " bra 4f\n" \ 223 " 3: move.l (%0)+,(%1)\n" \ 224 "31: move.l (%0)+,(%1)\n" \ 225 "32: move.l (%0)+,(%1)\n" \ 226 "33: move.l (%0)+,(%1)\n" \ 227 "34: move.l (%0)+,(%1)\n" \ 228 "35: move.l (%0)+,(%1)\n" \ 229 "36: move.l (%0)+,(%1)\n" \ 230 "37: move.l (%0)+,(%1)\n" \ 231 " 4: dbf %%d0,3b\n" \ 232 " move.w %2,%%d0\n" \ 233 " lsr.w #2,%%d0\n" \ 234 " and.w #7,%%d0\n" \ 235 " bra 6f\n" \ 236 " 5: move.l (%0)+,(%1)\n" \ 237 " 6: dbf %%d0,5b\n" \ 238 " and.w #3,%2\n" \ 239 " bra 8f\n" \ 240 " 7: move.b (%0)+,(%1)\n" \ 241 " 8: dbf %2,7b\n" \ 242 " moveq.l #0, %2\n" \ 243 " 9: \n" \ 244 ".section .fixup,\"ax\"\n" \ 245 " .even\n" \ 246 "90: moveq.l #1, %2\n" \ 247 " jra 9b\n" \ 248 ".previous\n" \ 249 ".section __ex_table,\"a\"\n" \ 250 " .align 4\n" \ 251 " .long 1b,90b\n" \ 252 " .long 3b,90b\n" \ 253 " .long 31b,90b\n" \ 254 " .long 32b,90b\n" \ 255 " .long 33b,90b\n" \ 256 " .long 34b,90b\n" \ 257 " .long 35b,90b\n" \ 258 " .long 36b,90b\n" \ 259 " .long 37b,90b\n" \ 260 " .long 5b,90b\n" \ 261 " .long 7b,90b\n" \ 262 ".previous" \ 263 : "=a"(s), "=a"(d), "=d"(len) \ 264 : "0"(s), "1"(d), "2"(len) \ 265 : "d0") 266 267 static int macscsi_pwrite(struct Scsi_Host *instance, 268 unsigned char *src, int len) 269 { 270 struct NCR5380_hostdata *hostdata = shost_priv(instance); 271 unsigned char *s; 272 unsigned char *d; 273 274 s = src; 275 d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4); 276 277 /* These conditions are derived from MacOS */ 278 279 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && 280 (!(NCR5380_read(STATUS_REG) & SR_REQ) || 281 (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) 282 ; 283 284 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) { 285 pr_err("Error in macscsi_pwrite\n"); 286 return -1; 287 } 288 289 CP_MEM_TO_IO(s, d, len); 290 291 if (len != 0) { 292 pr_notice("Bus error in macscsi_pwrite\n"); 293 return -1; 294 } 295 296 return 0; 297 } 298 299 static int macscsi_dma_xfer_len(struct Scsi_Host *instance, 300 struct scsi_cmnd *cmd) 301 { 302 struct NCR5380_hostdata *hostdata = shost_priv(instance); 303 304 if (hostdata->flags & FLAG_NO_PSEUDO_DMA) 305 return 0; 306 307 return cmd->transfersize; 308 } 309 310 #include "NCR5380.c" 311 312 #define DRV_MODULE_NAME "mac_scsi" 313 #define PFX DRV_MODULE_NAME ": " 314 315 static struct scsi_host_template mac_scsi_template = { 316 .module = THIS_MODULE, 317 .proc_name = DRV_MODULE_NAME, 318 .name = "Macintosh NCR5380 SCSI", 319 .info = macscsi_info, 320 .queuecommand = macscsi_queue_command, 321 .eh_abort_handler = macscsi_abort, 322 .eh_bus_reset_handler = macscsi_bus_reset, 323 .can_queue = 16, 324 .this_id = 7, 325 .sg_tablesize = SG_ALL, 326 .cmd_per_lun = 2, 327 .use_clustering = DISABLE_CLUSTERING, 328 .cmd_size = NCR5380_CMD_SIZE, 329 .max_sectors = 128, 330 }; 331 332 static int __init mac_scsi_probe(struct platform_device *pdev) 333 { 334 struct Scsi_Host *instance; 335 int error; 336 int host_flags = 0; 337 struct resource *irq, *pio_mem, *pdma_mem = NULL; 338 339 pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 340 if (!pio_mem) 341 return -ENODEV; 342 343 pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); 344 345 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 346 347 if (!hwreg_present((unsigned char *)pio_mem->start + 348 (STATUS_REG << 4))) { 349 pr_info(PFX "no device detected at %pap\n", &pio_mem->start); 350 return -ENODEV; 351 } 352 353 if (setup_can_queue > 0) 354 mac_scsi_template.can_queue = setup_can_queue; 355 if (setup_cmd_per_lun > 0) 356 mac_scsi_template.cmd_per_lun = setup_cmd_per_lun; 357 if (setup_sg_tablesize >= 0) 358 mac_scsi_template.sg_tablesize = setup_sg_tablesize; 359 if (setup_hostid >= 0) 360 mac_scsi_template.this_id = setup_hostid & 7; 361 if (setup_use_pdma < 0) 362 setup_use_pdma = 0; 363 364 instance = scsi_host_alloc(&mac_scsi_template, 365 sizeof(struct NCR5380_hostdata)); 366 if (!instance) 367 return -ENOMEM; 368 369 instance->base = pio_mem->start; 370 if (irq) 371 instance->irq = irq->start; 372 else 373 instance->irq = NO_IRQ; 374 375 if (pdma_mem && setup_use_pdma) { 376 struct NCR5380_hostdata *hostdata = shost_priv(instance); 377 378 hostdata->pdma_base = (unsigned char *)pdma_mem->start; 379 } else 380 host_flags |= FLAG_NO_PSEUDO_DMA; 381 382 host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0; 383 384 error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP); 385 if (error) 386 goto fail_init; 387 388 if (instance->irq != NO_IRQ) { 389 error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED, 390 "NCR5380", instance); 391 if (error) 392 goto fail_irq; 393 } 394 395 NCR5380_maybe_reset_bus(instance); 396 397 error = scsi_add_host(instance, NULL); 398 if (error) 399 goto fail_host; 400 401 platform_set_drvdata(pdev, instance); 402 403 scsi_scan_host(instance); 404 return 0; 405 406 fail_host: 407 if (instance->irq != NO_IRQ) 408 free_irq(instance->irq, instance); 409 fail_irq: 410 NCR5380_exit(instance); 411 fail_init: 412 scsi_host_put(instance); 413 return error; 414 } 415 416 static int __exit mac_scsi_remove(struct platform_device *pdev) 417 { 418 struct Scsi_Host *instance = platform_get_drvdata(pdev); 419 420 scsi_remove_host(instance); 421 if (instance->irq != NO_IRQ) 422 free_irq(instance->irq, instance); 423 NCR5380_exit(instance); 424 scsi_host_put(instance); 425 return 0; 426 } 427 428 static struct platform_driver mac_scsi_driver = { 429 .remove = __exit_p(mac_scsi_remove), 430 .driver = { 431 .name = DRV_MODULE_NAME, 432 }, 433 }; 434 435 module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe); 436 437 MODULE_ALIAS("platform:" DRV_MODULE_NAME); 438 MODULE_LICENSE("GPL"); 439