561 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic Macintosh NCR5380 driver4 *5 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>6 *7 * Copyright 2019 Finn Thain8 *9 * derived in part from:10 */11/*12 * Generic Generic NCR5380 driver13 *14 * Copyright 1995, Russell King15 */16 17#include <linux/delay.h>18#include <linux/types.h>19#include <linux/module.h>20#include <linux/ioport.h>21#include <linux/init.h>22#include <linux/blkdev.h>23#include <linux/interrupt.h>24#include <linux/platform_device.h>25 26#include <asm/hwtest.h>27#include <asm/io.h>28#include <asm/macintosh.h>29#include <asm/macints.h>30#include <asm/setup.h>31 32#include <scsi/scsi_host.h>33 34/* Definitions for the core NCR5380 driver. */35 36#define NCR5380_implementation_fields int pdma_residual37 38#define NCR5380_read(reg) in_8(hostdata->io + ((reg) << 4))39#define NCR5380_write(reg, value) out_8(hostdata->io + ((reg) << 4), value)40 41#define NCR5380_dma_xfer_len macscsi_dma_xfer_len42#define NCR5380_dma_recv_setup macscsi_pread43#define NCR5380_dma_send_setup macscsi_pwrite44#define NCR5380_dma_residual macscsi_dma_residual45 46#define NCR5380_intr macscsi_intr47#define NCR5380_queue_command macscsi_queue_command48#define NCR5380_abort macscsi_abort49#define NCR5380_host_reset macscsi_host_reset50#define NCR5380_info macscsi_info51 52#include "NCR5380.h"53 54static int setup_can_queue = -1;55module_param(setup_can_queue, int, 0);56static int setup_cmd_per_lun = -1;57module_param(setup_cmd_per_lun, int, 0);58static int setup_sg_tablesize = -1;59module_param(setup_sg_tablesize, int, 0);60static int setup_use_pdma = 512;61module_param(setup_use_pdma, int, 0);62static int setup_hostid = -1;63module_param(setup_hostid, int, 0);64static int setup_toshiba_delay = -1;65module_param(setup_toshiba_delay, int, 0);66 67#ifndef MODULE68static int __init mac_scsi_setup(char *str)69{70 int ints[8];71 72 (void)get_options(str, ARRAY_SIZE(ints), ints);73 74 if (ints[0] < 1) {75 pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");76 return 0;77 }78 if (ints[0] >= 1)79 setup_can_queue = ints[1];80 if (ints[0] >= 2)81 setup_cmd_per_lun = ints[2];82 if (ints[0] >= 3)83 setup_sg_tablesize = ints[3];84 if (ints[0] >= 4)85 setup_hostid = ints[4];86 /* ints[5] (use_tagged_queuing) is ignored */87 if (ints[0] >= 6)88 setup_use_pdma = ints[6];89 if (ints[0] >= 7)90 setup_toshiba_delay = ints[7];91 return 1;92}93 94__setup("mac5380=", mac_scsi_setup);95#endif /* !MODULE */96 97/*98 * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to99 * specify the number of bytes between the delays expected from a SCSI target.100 * This allows the operating system to "prevent bus errors when a target fails101 * to deliver the next byte within the processor bus error timeout period."102 * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets103 * so bus errors are unavoidable.104 *105 * If a MOVE.B instruction faults during a receive operation, we assume the106 * target sent nothing and try again. That assumption probably depends on107 * target firmware but it seems to hold up okay. If a fault happens during a108 * send operation, the target may or may not have seen /ACK and got the byte.109 * It's uncertain so the whole SCSI command gets retried.110 *111 * The NOP is needed for synchronization because the fault address in the112 * exception stack frame may or may not be the instruction that actually113 * caused the bus error. Post-increment addressing can't be used.114 */115 116#define MOVE_BYTE(operands) \117 asm volatile ( \118 "1: moveb " operands " \n" \119 "11: nop \n" \120 " addq #1,%0 \n" \121 " subq #1,%1 \n" \122 "40: \n" \123 " \n" \124 ".section .fixup,\"ax\" \n" \125 ".even \n" \126 "90: movel #1, %2 \n" \127 " jra 40b \n" \128 ".previous \n" \129 " \n" \130 ".section __ex_table,\"a\" \n" \131 ".align 4 \n" \132 ".long 1b,90b \n" \133 ".long 11b,90b \n" \134 ".previous \n" \135 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))136 137/*138 * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because139 * the residual byte count would be uncertain. In that situation the MOVE_WORD140 * macro clears n in the fixup section to abort the transfer.141 */142 143#define MOVE_WORD(operands) \144 asm volatile ( \145 "1: movew " operands " \n" \146 "11: nop \n" \147 " subq #2,%1 \n" \148 "40: \n" \149 " \n" \150 ".section .fixup,\"ax\" \n" \151 ".even \n" \152 "90: movel #0, %1 \n" \153 " movel #2, %2 \n" \154 " jra 40b \n" \155 ".previous \n" \156 " \n" \157 ".section __ex_table,\"a\" \n" \158 ".align 4 \n" \159 ".long 1b,90b \n" \160 ".long 11b,90b \n" \161 ".previous \n" \162 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))163 164#define MOVE_16_WORDS(operands) \165 asm volatile ( \166 "1: movew " operands " \n" \167 "2: movew " operands " \n" \168 "3: movew " operands " \n" \169 "4: movew " operands " \n" \170 "5: movew " operands " \n" \171 "6: movew " operands " \n" \172 "7: movew " operands " \n" \173 "8: movew " operands " \n" \174 "9: movew " operands " \n" \175 "10: movew " operands " \n" \176 "11: movew " operands " \n" \177 "12: movew " operands " \n" \178 "13: movew " operands " \n" \179 "14: movew " operands " \n" \180 "15: movew " operands " \n" \181 "16: movew " operands " \n" \182 "17: nop \n" \183 " subl #32,%1 \n" \184 "40: \n" \185 " \n" \186 ".section .fixup,\"ax\" \n" \187 ".even \n" \188 "90: movel #0, %1 \n" \189 " movel #2, %2 \n" \190 " jra 40b \n" \191 ".previous \n" \192 " \n" \193 ".section __ex_table,\"a\" \n" \194 ".align 4 \n" \195 ".long 1b,90b \n" \196 ".long 2b,90b \n" \197 ".long 3b,90b \n" \198 ".long 4b,90b \n" \199 ".long 5b,90b \n" \200 ".long 6b,90b \n" \201 ".long 7b,90b \n" \202 ".long 8b,90b \n" \203 ".long 9b,90b \n" \204 ".long 10b,90b \n" \205 ".long 11b,90b \n" \206 ".long 12b,90b \n" \207 ".long 13b,90b \n" \208 ".long 14b,90b \n" \209 ".long 15b,90b \n" \210 ".long 16b,90b \n" \211 ".long 17b,90b \n" \212 ".previous \n" \213 : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))214 215static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)216{217 unsigned char *addr = start;218 int result = 0;219 220 if (n >= 1) {221 MOVE_BYTE("%3@,%0@");222 if (result)223 goto out;224 }225 if (n >= 1 && ((unsigned long)addr & 1)) {226 MOVE_BYTE("%3@,%0@");227 if (result)228 goto out;229 }230 while (n >= 32)231 MOVE_16_WORDS("%3@,%0@+");232 while (n >= 2)233 MOVE_WORD("%3@,%0@+");234 if (result)235 return start - addr; /* Negated to indicate uncertain length */236 if (n == 1)237 MOVE_BYTE("%3@,%0@");238out:239 return addr - start;240}241 242static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)243{244 unsigned char *addr = start;245 int result = 0;246 247 if (n >= 1) {248 MOVE_BYTE("%0@,%3@");249 if (result)250 return -1;251 }252 if (n >= 1 && ((unsigned long)addr & 1)) {253 MOVE_BYTE("%0@,%3@");254 if (result)255 return -2;256 }257 while (n >= 32)258 MOVE_16_WORDS("%0@+,%3@");259 while (n >= 2)260 MOVE_WORD("%0@+,%3@");261 if (result)262 return start - addr - 1; /* Negated to indicate uncertain length */263 if (n == 1)264 MOVE_BYTE("%0@,%3@");265 return addr - start;266}267 268/* The "SCSI DMA" chip on the IIfx implements this register. */269#define CTRL_REG 0x8270#define CTRL_INTERRUPTS_ENABLE BIT(1)271#define CTRL_HANDSHAKE_MODE BIT(3)272 273static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)274{275 out_be32(hostdata->io + (CTRL_REG << 4), value);276}277 278static inline int macscsi_wait_for_drq(struct NCR5380_hostdata *hostdata)279{280 unsigned int n = 1; /* effectively multiplies NCR5380_REG_POLL_TIME */281 unsigned char basr;282 283again:284 basr = NCR5380_read(BUS_AND_STATUS_REG);285 286 if (!(basr & BASR_PHASE_MATCH))287 return 1;288 289 if (basr & BASR_IRQ)290 return -1;291 292 if (basr & BASR_DRQ)293 return 0;294 295 if (n-- == 0) {296 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);297 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,298 "%s: DRQ timeout\n", __func__);299 return -1;300 }301 302 NCR5380_poll_politely2(hostdata,303 BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,304 BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0);305 goto again;306}307 308static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,309 unsigned char *dst, int len)310{311 u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);312 unsigned char *d = dst;313 314 hostdata->pdma_residual = len;315 316 while (macscsi_wait_for_drq(hostdata) == 0) {317 int bytes, chunk_bytes;318 319 if (macintosh_config->ident == MAC_MODEL_IIFX)320 write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |321 CTRL_INTERRUPTS_ENABLE);322 323 chunk_bytes = min(hostdata->pdma_residual, 512);324 bytes = mac_pdma_recv(s, d, chunk_bytes);325 326 if (macintosh_config->ident == MAC_MODEL_IIFX)327 write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);328 329 if (bytes > 0) {330 d += bytes;331 hostdata->pdma_residual -= bytes;332 }333 334 if (hostdata->pdma_residual == 0)335 break;336 337 if (bytes > 0)338 continue;339 340 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);341 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,342 "%s: bus error [%d/%d] (%d/%d)\n",343 __func__, d - dst, len, bytes, chunk_bytes);344 345 if (bytes == 0)346 continue;347 348 if (macscsi_wait_for_drq(hostdata) <= 0)349 set_host_byte(hostdata->connected, DID_ERROR);350 break;351 }352 353 return 0;354}355 356static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,357 unsigned char *src, int len)358{359 unsigned char *s = src;360 u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);361 362 hostdata->pdma_residual = len;363 364 while (macscsi_wait_for_drq(hostdata) == 0) {365 int bytes, chunk_bytes;366 367 if (macintosh_config->ident == MAC_MODEL_IIFX)368 write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |369 CTRL_INTERRUPTS_ENABLE);370 371 chunk_bytes = min(hostdata->pdma_residual, 512);372 bytes = mac_pdma_send(s, d, chunk_bytes);373 374 if (macintosh_config->ident == MAC_MODEL_IIFX)375 write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);376 377 if (bytes > 0) {378 s += bytes;379 hostdata->pdma_residual -= bytes;380 }381 382 if (hostdata->pdma_residual == 0)383 break;384 385 if (bytes > 0)386 continue;387 388 NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);389 dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,390 "%s: bus error [%d/%d] (%d/%d)\n",391 __func__, s - src, len, bytes, chunk_bytes);392 393 if (bytes == 0)394 continue;395 396 if (macscsi_wait_for_drq(hostdata) <= 0)397 set_host_byte(hostdata->connected, DID_ERROR);398 break;399 }400 401 return 0;402}403 404static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,405 struct scsi_cmnd *cmd)406{407 int resid = NCR5380_to_ncmd(cmd)->this_residual;408 409 if (hostdata->flags & FLAG_NO_PSEUDO_DMA || resid < setup_use_pdma)410 return 0;411 412 return resid;413}414 415static int macscsi_dma_residual(struct NCR5380_hostdata *hostdata)416{417 return hostdata->pdma_residual;418}419 420#include "NCR5380.c"421 422#define DRV_MODULE_NAME "mac_scsi"423#define PFX DRV_MODULE_NAME ": "424 425static struct scsi_host_template mac_scsi_template = {426 .module = THIS_MODULE,427 .proc_name = DRV_MODULE_NAME,428 .name = "Macintosh NCR5380 SCSI",429 .info = macscsi_info,430 .queuecommand = macscsi_queue_command,431 .eh_abort_handler = macscsi_abort,432 .eh_host_reset_handler = macscsi_host_reset,433 .can_queue = 16,434 .this_id = 7,435 .sg_tablesize = SG_ALL,436 .cmd_per_lun = 2,437 .dma_boundary = PAGE_SIZE - 1,438 .cmd_size = sizeof(struct NCR5380_cmd),439 .max_sectors = 128,440};441 442static int __init mac_scsi_probe(struct platform_device *pdev)443{444 struct Scsi_Host *instance;445 struct NCR5380_hostdata *hostdata;446 int error;447 int host_flags = 0;448 struct resource *irq, *pio_mem, *pdma_mem = NULL;449 450 pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);451 if (!pio_mem)452 return -ENODEV;453 454 pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);455 456 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);457 458 if (!hwreg_present((unsigned char *)pio_mem->start +459 (STATUS_REG << 4))) {460 pr_info(PFX "no device detected at %pap\n", &pio_mem->start);461 return -ENODEV;462 }463 464 if (setup_can_queue > 0)465 mac_scsi_template.can_queue = setup_can_queue;466 if (setup_cmd_per_lun > 0)467 mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;468 if (setup_sg_tablesize > 0)469 mac_scsi_template.sg_tablesize = setup_sg_tablesize;470 if (setup_hostid >= 0)471 mac_scsi_template.this_id = setup_hostid & 7;472 473 if (macintosh_config->ident == MAC_MODEL_IIFX)474 mac_scsi_template.sg_tablesize = 1;475 476 instance = scsi_host_alloc(&mac_scsi_template,477 sizeof(struct NCR5380_hostdata));478 if (!instance)479 return -ENOMEM;480 481 if (irq)482 instance->irq = irq->start;483 else484 instance->irq = NO_IRQ;485 486 hostdata = shost_priv(instance);487 hostdata->base = pio_mem->start;488 hostdata->io = (u8 __iomem *)pio_mem->start;489 490 if (pdma_mem && setup_use_pdma)491 hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;492 else493 host_flags |= FLAG_NO_PSEUDO_DMA;494 495 host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;496 497 if (instance->sg_tablesize > 1)498 host_flags |= FLAG_DMA_FIXUP;499 500 error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);501 if (error)502 goto fail_init;503 504 if (instance->irq != NO_IRQ) {505 error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,506 "NCR5380", instance);507 if (error)508 goto fail_irq;509 }510 511 NCR5380_maybe_reset_bus(instance);512 513 error = scsi_add_host(instance, NULL);514 if (error)515 goto fail_host;516 517 platform_set_drvdata(pdev, instance);518 519 scsi_scan_host(instance);520 return 0;521 522fail_host:523 if (instance->irq != NO_IRQ)524 free_irq(instance->irq, instance);525fail_irq:526 NCR5380_exit(instance);527fail_init:528 scsi_host_put(instance);529 return error;530}531 532static void __exit mac_scsi_remove(struct platform_device *pdev)533{534 struct Scsi_Host *instance = platform_get_drvdata(pdev);535 536 scsi_remove_host(instance);537 if (instance->irq != NO_IRQ)538 free_irq(instance->irq, instance);539 NCR5380_exit(instance);540 scsi_host_put(instance);541}542 543/*544 * mac_scsi_remove() lives in .exit.text. For drivers registered via545 * module_platform_driver_probe() this is ok because they cannot get unbound at546 * runtime. So mark the driver struct with __refdata to prevent modpost547 * triggering a section mismatch warning.548 */549static struct platform_driver mac_scsi_driver __refdata = {550 .remove_new = __exit_p(mac_scsi_remove),551 .driver = {552 .name = DRV_MODULE_NAME,553 },554};555 556module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);557 558MODULE_ALIAS("platform:" DRV_MODULE_NAME);559MODULE_DESCRIPTION("Macintosh NCR5380 SCSI driver");560MODULE_LICENSE("GPL");561