brintos

brintos / linux-shallow public Read only

0
0
Text · 15.4 KiB · f225bb2 Raw
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