📄 53c78xx.c
字号:
* we do this, we need to handle the case where we disconnect * between segments. * * 2. Currently, when Icky things happen we do a FATAL(). Instead, * we want to do an integrity check on the parts of the NCR hostdata * structure which were initialized at boot time; FATAL() if that * fails, and otherwise try to recover. Keep track of how many * times this has happened within a single SCSI command; if it * gets excessive, then FATAL(). * * 3. Parity checking is currently disabled, and a few things should * happen here now that we support synchronous SCSI transfers : * 1. On soft-reset, we should set the EPC (Enable Parity Checking) * and AAP (Assert SATN/ on parity error) bits in SCNTL0. * * 2. We should enable the parity interrupt in the SIEN0 register. * * 3. intr_phase_mismatch() needs to believe that message out is * always an "acceptable" phase to have a mismatch in. If * the old phase was MSG_IN, we should send a MESSAGE PARITY * error. If the old phase was something else, we should send * a INITIATOR_DETECTED_ERROR message. Note that this could * cause a RESTORE POINTERS message; so we should handle that * correctly first. Instead, we should probably do an * initiator_abort. * * 4. MPEE bit of CTEST4 should be set so we get interrupted if * we detect an error. * * * 5. The initial code has been tested on the NCR53c810. I don't * have access to NCR53c700, 700-66 (Forex boards), NCR53c710 * (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to * finish development on those platforms. * * NCR53c820/825/720 - need to add wide transfer support, including WDTR * negotiation, programming of wide transfer capabilities * on reselection and table indirect selection. * * NCR53c710 - need to add fatal interrupt or GEN code for * command completion signaling. Need to modify all * SDID, SCID, etc. registers, and table indirect select code * since these use bit fielded (ie 1<<target) instead of * binary encoded target ids. Need to accommodate * different register mappings, probably scan through * the SCRIPT code and change the non SFBR register operand * of all MOVE instructions. * * NCR53c700/700-66 - need to add code to refix addresses on * every nexus change, eliminate all table indirect code, * very messy. * * 6. The NCR53c7x0 series is very popular on other platforms that * could be running Linux - ie, some high performance AMIGA SCSI * boards use it. * * So, I should include #ifdef'd code so that it is * compatible with these systems. * * Specifically, the little Endian assumptions I made in my * bit fields need to change, and if the NCR doesn't see memory * the right way, we need to provide options to reverse words * when the scripts are relocated. * * 7. Use vremap() to access memory mapped boards. *//* * Allow for simultaneous existence of multiple SCSI scripts so we * can have a single driver binary for all of the family. * * - one for NCR53c700 and NCR53c700-66 chips (not yet supported) * - one for rest (only the NCR53c810, 815, 820, and 825 are currently * supported) * * So that we only need two SCSI scripts, we need to modify things so * that we fixup register accesses in READ/WRITE instructions, and * we'll also have to accommodate the bit vs. binary encoding of IDs * with the 7xx chips. *//* * Use pci_chips_ids to translate in both directions between PCI device ID * and chip numbers. */static struct { unsigned short pci_device_id; int chip;/* * The revision field of the PCI_CLASS_REVISION register is compared * against each of these fields if the field is not -1. If it * is less than min_revision or larger than max_revision, a warning * message is printed. */ int max_revision; int min_revision;} pci_chip_ids[] = { {PCI_DEVICE_ID_NCR_53C810, 810, 2, 1}, {PCI_DEVICE_ID_NCR_53C815, 815, 3, 2}, {PCI_DEVICE_ID_NCR_53C820, 820, -1, -1}, {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1}};#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))#define ROUNDUP(adr,type) \ ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))/* * Forced detection and autoprobe code for various hardware. Currently, * entry points for these are not included in init/main.c because if the * PCI BIOS code isn't working right, you're not going to be able to use * the hardware anyways; this way we force users to solve their * problems rather than forcing detection and blaming us when it * does not work. */static struct override { int chip; /* 700, 70066, 710, 720, 810, 820 */ int board; /* Any special board level gunk */ unsigned pci:1; union { struct { int base; /* Memory address - indicates memory mapped regs */ int io_port;/* I/O port address - indicates I/O mapped regs */ int irq; /* IRQ line */ int dma; /* DMA channel - often none */ } normal; struct { int bus; int device; int function; } pci; } data; long long options;} overrides [4] = {{0,},};static int commandline_current = 0;static int no_overrides = 0;#if 0#define OVERRIDE_LIMIT (sizeof(overrides) / sizeof(struct override))#else#define OVERRIDE_LIMIT commandline_current#endif/* * Function: issue_to_cmd * * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd * structure pointer. * * Inputs; issue - pointer to start of NOP or JUMP instruction * in issue array. * * Returns: pointer to command on success; 0 if opcode is NOP. */static inline struct NCR53c7x0_cmd *issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, u32 *issue){ return (issue[0] != hostdata->NOP_insn) ? /* * If the IF TRUE bit is set, it's a JUMP instruction. The * operand is a bus pointer to the dsa_begin routine for this DSA. The * dsa field of the NCR53c7x0_cmd structure starts with the * DSA code template. By converting to a virtual address, * subtracting the code template size, and offset of the * dsa field, we end up with a pointer to the start of the * structure (alternatively, we could use the * dsa_cmnd field, an anachronism from when we weren't * sure what the relationship between the NCR structures * and host structures were going to be. */ (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) - (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) - offsetof(struct NCR53c7x0_cmd, dsa)) /* If the IF TRUE bit is not set, it's a NOP */ : NULL;}/* * Function : static internal_setup(int board, int chip, char *str, int *ints) * * Purpose : LILO command line initialization of the overrides array, * * Inputs : board - currently, unsupported. chip - 700, 70066, 710, 720 * 810, 815, 820, 825, although currently only the NCR53c810 is * supported. * */static void internal_setup(int board, int chip, char *str, int *ints) { unsigned char pci; /* Specifies a PCI override, with bus, device, function */ pci = (str && !strcmp (str, "pci")) ? 1 : 0; /* * Override syntaxes are as follows : * ncr53c700,ncr53c700-66,ncr53c710,ncr53c720=mem,io,irq,dma * ncr53c810,ncr53c820,ncr53c825=mem,io,irq or pci,bus,device,function */ if (commandline_current < OVERRIDE_LIMIT) { overrides[commandline_current].pci = pci ? 1 : 0; if (!pci) { overrides[commandline_current].data.normal.base = ints[1]; overrides[commandline_current].data.normal.io_port = ints[2]; overrides[commandline_current].data.normal.irq = ints[3]; overrides[commandline_current].data.normal.dma = (ints[0] >= 4) ? ints[4] : DMA_NONE; /* FIXME: options is now a long long */ overrides[commandline_current].options = (ints[0] >= 5) ? ints[5] : 0; } else { overrides[commandline_current].data.pci.bus = ints[1]; overrides[commandline_current].data.pci.device = ints[2]; overrides[commandline_current].data.pci.function = ints[3]; /* FIXME: options is now a long long */ overrides[commandline_current].options = (ints[0] >= 4) ? ints[4] : 0; } overrides[commandline_current].board = board; overrides[commandline_current].chip = chip; ++commandline_current; ++no_overrides; } else { printk ("53c7,7x0.c:internal_setup() : too many overrides\n"); }}/* * XXX - we might want to implement a single override function * with a chip type field, revamp the command line configuration, * etc. */#define setup_wrapper(x) \void ncr53c##x##_setup (char *str, int *ints) { \ internal_setup (BOARD_GENERIC, x, str, ints); \}setup_wrapper(700)setup_wrapper(70066)setup_wrapper(710)setup_wrapper(720)setup_wrapper(810)setup_wrapper(815)setup_wrapper(820)setup_wrapper(825)/* * FIXME: we should junk these, in favor of synchronous_want and * wide_want in the NCR53c7x0_hostdata structure. *//* Template for "preferred" synchronous transfer parameters. */static const unsigned char sdtr_message[] = {#ifdef CONFIG_SCSI_NCR53C7xx_FAST EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */ #else EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */ #endif};/* Template to request asynchronous transfers */static const unsigned char async_message[] = { EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */};/* Template for "preferred" WIDE transfer parameters */static const unsigned char wdtr_message[] = { EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */};/* * Function : struct Scsi_Host *find_host (int host) * * Purpose : KGDB support function which translates a host number * to a host structure. * * Inputs : host - number of SCSI host * * Returns : NULL on failure, pointer to host structure on success. */static struct Scsi_Host *find_host (int host) { struct Scsi_Host *h; for (h = first_host; h && h->host_no != host; h = h->next); if (!h) { printk (KERN_ALERT "scsi%d not found\n", host); return NULL; } else if (h->hostt != the_template) { printk (KERN_ALERT "scsi%d is not a NCR board\n", host); return NULL; } return h;}/* * Function : request_synchronous (int host, int target) * * Purpose : KGDB interface which will allow us to negotiate for * synchronous transfers. This ill be replaced with a more * integrated function; perhaps a new entry in the scsi_host * structure, accessible via an ioctl() or perhaps /proc/scsi. * * Inputs : host - number of SCSI host; target - number of target. * * Returns : 0 when negotiation has been setup for next SCSI command, * -1 on failure. */static intrequest_synchronous (int host, int target) { struct Scsi_Host *h; struct NCR53c7x0_hostdata *hostdata; unsigned long flags; if (target < 0) { printk (KERN_ALERT "target %d is bogus\n", target); return -1; } if (!(h = find_host (host))) return -1; else if (h->this_id == target) { printk (KERN_ALERT "target %d is host ID\n", target); return -1; } #ifndef LINUX_1_2 else if (target > h->max_id) { printk (KERN_ALERT "target %d exceeds maximum of %d\n", target, h->max_id); return -1; }#endif hostdata = (struct NCR53c7x0_hostdata *)h->hostdata; save_flags(flags); cli(); if (hostdata->initiate_sdtr & (1 << target)) { restore_flags(flags); printk (KERN_ALERT "target %d already doing SDTR\n", target); return -1; } hostdata->initiate_sdtr |= (1 << target); restore_flags(flags); return 0;}/* * Function : request_disconnect (int host, int on_or_off) * * Purpose : KGDB support function, tells us to allow or disallow * disconnections. * * Inputs : host - number of SCSI host; on_or_off - non-zero to allow, * zero to disallow. * * Returns : 0 on success, * -1 on failure. */static int request_disconnect (int host, int on_or_off) { struct Scsi_Host *h; struct NCR53c7x0_hostdata *hostdata; if (!(h = find_host (host))) return -1; hostdata = (struct NCR53c7x0_hostdata *) h->hostdata; if (on_or_off) hostdata->options |= OPTION_DISCONNECT; else hostdata->options &= ~OPTION_DISCONNECT; return 0;}/* * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host) * * Purpose : Initialize internal structures, as required on startup, or * after a SCSI bus reset. * * Inputs : host - pointer to this host adapter's structure
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -