diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-06 01:05:53 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-06 01:05:53 +0300 |
commit | 052c220da392c4dcbc628852d04970447a315683 (patch) | |
tree | b251b5c977152c1c63c51ed625ee1b31a8741851 /drivers/scsi | |
parent | 3526dd0c7832f1011a0477cc6d903662bae05ea8 (diff) | |
parent | 2e1f44f6ad8008be353c7c99286f7a747b4b3cf4 (diff) | |
download | linux-052c220da392c4dcbc628852d04970447a315683.tar.xz |
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This is mostly updates of the usual drivers: arcmsr, qla2xx, lpfc,
ufs, mpt3sas, hisi_sas.
In addition we have removed several really old drivers: sym53c416,
NCR53c406a, fdomain, fdomain_cs and removed the old scsi_module.c
initialization from all remaining drivers.
Plus an assortment of bug fixes, initialization errors and other minor
fixes"
* tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (168 commits)
scsi: ufs: Add support for Auto-Hibernate Idle Timer
scsi: ufs: sysfs: reworking of the rpm_lvl and spm_lvl entries
scsi: qla2xxx: fx00 copypaste typo
scsi: qla2xxx: fix error message on <qla2400
scsi: smartpqi: update driver version
scsi: smartpqi: workaround fw bug for oq deletion
scsi: arcmsr: Change driver version to v1.40.00.05-20180309
scsi: arcmsr: Sleep to avoid CPU stuck too long for waiting adapter ready
scsi: arcmsr: Handle adapter removed due to thunderbolt cable disconnection.
scsi: arcmsr: Rename ACB_F_BUS_HANG_ON to ACB_F_ADAPTER_REMOVED for adapter hot-plug
scsi: qla2xxx: Update driver version to 10.00.00.06-k
scsi: qla2xxx: Fix Async GPN_FT for FCP and FC-NVMe scan
scsi: qla2xxx: Cleanup code to improve FC-NVMe error handling
scsi: qla2xxx: Fix FC-NVMe IO abort during driver reset
scsi: qla2xxx: Fix retry for PRLI RJT with reason of BUSY
scsi: qla2xxx: Remove nvme_done_list
scsi: qla2xxx: Return busy if rport going away
scsi: qla2xxx: Fix n2n_ae flag to prevent dev_loss on PDB change
scsi: qla2xxx: Add FC-NVMe abort processing
scsi: qla2xxx: Add changes for devloss timeout in driver
...
Diffstat (limited to 'drivers/scsi')
154 files changed, 5293 insertions, 10408 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8a739b74cfb7..11e89e56b865 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -640,88 +640,6 @@ config SCSI_DMX3191D To compile this driver as a module, choose M here: the module will be called dmx3191d. -config SCSI_EATA - tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API - ---help--- - This driver supports all EATA/DMA-compliant SCSI host adapters. DPT - ISA and all EISA I/O addresses are probed looking for the "EATA" - signature. The addresses of all the PCI SCSI controllers reported - by the PCI subsystem are probed as well. - - You want to read the start of <file:drivers/scsi/eata.c> and the - SCSI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here: the - module will be called eata. - -config SCSI_EATA_TAGGED_QUEUE - bool "enable tagged command queueing" - depends on SCSI_EATA - help - This is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. - This is equivalent to the "eata=tc:y" boot option. - -config SCSI_EATA_LINKED_COMMANDS - bool "enable elevator sorting" - depends on SCSI_EATA - help - This option enables elevator sorting for all probed SCSI disks and - CD-ROMs. It definitely reduces the average seek distance when doing - random seeks, but this does not necessarily result in a noticeable - performance improvement: your mileage may vary... - This is equivalent to the "eata=lc:y" boot option. - -config SCSI_EATA_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_EATA - default "16" - help - This specifies how many SCSI commands can be maximally queued for - each probed SCSI device. You should reduce the default value of 16 - only if you have disks with buggy or limited tagged command support. - Minimum is 2 and maximum is 62. This value is also the window size - used by the elevator sorting option above. The effective value used - by the driver for each probed SCSI device is reported at boot time. - This is equivalent to the "eata=mq:8" boot option. - -config SCSI_EATA_PIO - tristate "EATA-PIO (old DPT PM2001, PM2012A) support" - depends on (ISA || EISA || PCI) && SCSI && BROKEN - ---help--- - This driver supports all EATA-PIO protocol compliant SCSI Host - Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant - host adapters could also use this driver but are discouraged from - doing so, since this driver only supports hard disks and lacks - numerous features. You might want to have a look at the SCSI-HOWTO, - available from <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here: the - module will be called eata_pio. - -config SCSI_FUTURE_DOMAIN - tristate "Future Domain 16xx SCSI/AHA-2920A support" - depends on (ISA || PCI) && SCSI - select CHECK_SIGNATURE - ---help--- - This is support for Future Domain's 16-bit SCSI host adapters - (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and - other adapters based on the Future Domain chipsets (Quantum - ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). - It is explained in section 3.7 of the SCSI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip - and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI - controller support"). This Future Domain driver works with the older - Adaptec AHA-2920A boards with a Future Domain chip on them. - - To compile this driver as a module, choose M here: the - module will be called fdomain. - config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API @@ -923,18 +841,6 @@ config SCSI_IZIP_SLOW_CTR Generally, saying N is fine. -config SCSI_NCR53C406A - tristate "NCR53c406a SCSI support" - depends on ISA && SCSI - help - This is support for the NCR53c406a SCSI host adapter. For user - configurable parameters, check out <file:drivers/scsi/NCR53c406a.c> - in the kernel source. Also read the SCSI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here: the - module will be called NCR53c406. - config SCSI_NCR_D700 tristate "NCR Dual 700 MCA SCSI support" depends on MCA && SCSI @@ -1059,6 +965,7 @@ config SCSI_IPR depends on PCI && SCSI && ATA select FW_LOADER select IRQ_POLL + select SGL_ALLOC ---help--- This driver supports the IBM Power Linux family RAID adapters. This includes IBM pSeries 5712, 5703, 5709, and 570A, as well @@ -1265,24 +1172,6 @@ config SCSI_SIM710 It currently supports Compaq EISA cards and NCR MCA cards -config SCSI_SYM53C416 - tristate "Symbios 53c416 SCSI support" - depends on ISA && SCSI - ---help--- - This is support for the sym53c416 SCSI host adapter, the SCSI - adapter that comes with some HP scanners. This driver requires that - the sym53c416 is configured first using some sort of PnP - configuration program (e.g. isapnp) or by a PnP aware BIOS. If you - are using isapnp then you need to compile this driver as a module - and then load it using insmod after isapnp has run. The parameters - of the configured card(s) should be passed to the driver. The format - is: - - insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>] - - To compile this driver as a module, choose M here: the - module will be called sym53c416. - config SCSI_DC395x tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support" depends on PCI && SCSI @@ -1576,6 +1465,7 @@ config ZFCP config SCSI_PMCRAID tristate "PMC SIERRA Linux MaxRAID adapter support" depends on PCI && SCSI && NET + select SGL_ALLOC ---help--- This driver supports the PMC SIERRA MaxRAID adapters. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index de1b3fce936d..e29f9b8fd66d 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -74,12 +74,9 @@ obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/ obj-$(CONFIG_SCSI_PM8001) += pm8001/ obj-$(CONFIG_SCSI_ISCI) += isci/ obj-$(CONFIG_SCSI_IPS) += ips.o -obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o -obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o obj-$(CONFIG_SCSI_NCR_D700) += 53c700.o NCR_D700.o obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o -obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o @@ -93,8 +90,6 @@ obj-$(CONFIG_SCSI_HPSA) += hpsa.o obj-$(CONFIG_SCSI_SMARTPQI) += smartpqi/ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o -obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o -obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o obj-$(CONFIG_CXLFLASH) += cxlflash/ diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c deleted file mode 100644 index 6e110c630d2c..000000000000 --- a/drivers/scsi/NCR53c406a.c +++ /dev/null @@ -1,1090 +0,0 @@ -/* - * NCR53c406.c - * Low-level SCSI driver for NCR53c406a chip. - * Copyright (C) 1994, 1995, 1996 Normunds Saumanis (normunds@fi.ibm.com) - * - * LILO command line usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]] - * Specify IRQ = 0 for non-interrupt driven mode. - * FASTPIO = 1 for fast pio mode, 0 for slow mode. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#define NCR53C406A_DEBUG 0 -#define VERBOSE_NCR53C406A_DEBUG 0 - -/* Set this to 1 for PIO mode (recommended) or to 0 for DMA mode */ -#define USE_PIO 1 - -#define USE_BIOS 0 - /* #define BIOS_ADDR 0xD8000 *//* define this if autoprobe fails */ - /* #define PORT_BASE 0x330 *//* define this if autoprobe fails */ - /* #define IRQ_LEV 0 *//* define this if autoprobe fails */ -#define DMA_CHAN 5 /* this is ignored if DMA is disabled */ - -/* Set this to 0 if you encounter kernel lockups while transferring - * data in PIO mode */ -#define USE_FAST_PIO 1 - -/* ============= End of user configurable parameters ============= */ - -#include <linux/module.h> - -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/irq.h> - -#include <linux/blkdev.h> -#include <linux/spinlock.h> -#include "scsi.h" -#include <scsi/scsi_host.h> - -/* ============================================================= */ - -#define WATCHDOG 5000000 - -#define SYNC_MODE 0 /* Synchronous transfer mode */ - -#ifdef DEBUG -#undef NCR53C406A_DEBUG -#define NCR53C406A_DEBUG 1 -#endif - -#if USE_PIO -#define USE_DMA 0 -#else -#define USE_DMA 1 -#endif - -/* Default configuration */ -#define C1_IMG 0x07 /* ID=7 */ -#define C2_IMG 0x48 /* FE SCSI2 */ -#if USE_DMA -#define C3_IMG 0x21 /* CDB TE */ -#else -#define C3_IMG 0x20 /* CDB */ -#endif -#define C4_IMG 0x04 /* ANE */ -#define C5_IMG 0xb6 /* AA PI SIE POL */ - -#define REG0 (outb(C4_IMG, CONFIG4)) -#define REG1 (outb(C5_IMG, CONFIG5)) - -#if NCR53C406A_DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -#if VERBOSE_NCR53C406A_DEBUG -#define VDEB(x) x -#else -#define VDEB(x) -#endif - -#define LOAD_DMA_COUNT(count) \ - outb(count & 0xff, TC_LSB); \ - outb((count >> 8) & 0xff, TC_MSB); \ - outb((count >> 16) & 0xff, TC_HIGH); - -/* Chip commands */ -#define DMA_OP 0x80 - -#define SCSI_NOP 0x00 -#define FLUSH_FIFO 0x01 -#define CHIP_RESET 0x02 -#define SCSI_RESET 0x03 -#define RESELECT 0x40 -#define SELECT_NO_ATN 0x41 -#define SELECT_ATN 0x42 -#define SELECT_ATN_STOP 0x43 -#define ENABLE_SEL 0x44 -#define DISABLE_SEL 0x45 -#define SELECT_ATN3 0x46 -#define RESELECT3 0x47 -#define TRANSFER_INFO 0x10 -#define INIT_CMD_COMPLETE 0x11 -#define MSG_ACCEPT 0x12 -#define TRANSFER_PAD 0x18 -#define SET_ATN 0x1a -#define RESET_ATN 0x1b -#define SEND_MSG 0x20 -#define SEND_STATUS 0x21 -#define SEND_DATA 0x22 -#define DISCONN_SEQ 0x23 -#define TERMINATE_SEQ 0x24 -#define TARG_CMD_COMPLETE 0x25 -#define DISCONN 0x27 -#define RECV_MSG 0x28 -#define RECV_CMD 0x29 -#define RECV_DATA 0x2a -#define RECV_CMD_SEQ 0x2b -#define TARGET_ABORT_DMA 0x04 - -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ - -#if NCR53C406A_DEBUG -#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} -#else -#define rtrc(i) {} -#endif -/*----------------------------------------------------------------*/ - -enum Phase { - idle, - data_out, - data_in, - command_ph, - status_ph, - message_out, - message_in -}; - -/* Static function prototypes */ -static void NCR53c406a_intr(void *); -static irqreturn_t do_NCR53c406a_intr(int, void *); -static void chip_init(void); -static void calc_port_addr(void); -#ifndef IRQ_LEV -static int irq_probe(void); -#endif - -/* ================================================================= */ - -#if USE_BIOS -static void *bios_base; -#endif - -#ifdef PORT_BASE -static int port_base = PORT_BASE; -#else -static int port_base; -#endif - -#ifdef IRQ_LEV -static int irq_level = IRQ_LEV; -#else -static int irq_level = -1; /* 0 is 'no irq', so use -1 for 'uninitialized' */ -#endif - -#if USE_DMA -static int dma_chan; -#endif - -#if USE_PIO -static int fast_pio = USE_FAST_PIO; -#endif - -static Scsi_Cmnd *current_SC; -static char info_msg[256]; - -/* ================================================================= */ - -/* possible BIOS locations */ -#if USE_BIOS -static void *addresses[] = { - (void *) 0xd8000, - (void *) 0xc8000 -}; -#define ADDRESS_COUNT ARRAY_SIZE(addresses) -#endif /* USE_BIOS */ - -/* possible i/o port addresses */ -static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 }; -#define PORT_COUNT ARRAY_SIZE(ports) - -#ifndef MODULE -/* possible interrupt channels */ -static unsigned short intrs[] = { 10, 11, 12, 15 }; -#define INTR_COUNT ARRAY_SIZE(intrs) -#endif /* !MODULE */ - -/* signatures for NCR 53c406a based controllers */ -#if USE_BIOS -struct signature { - char *signature; - int sig_offset; - int sig_length; -} signatures[] __initdata = { - /* 1 2 3 4 5 6 */ - /* 123456789012345678901234567890123456789012345678901234567890 */ - { -"Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82},}; - -#define SIGNATURE_COUNT ARRAY_SIZE(signatures) -#endif /* USE_BIOS */ - -/* ============================================================ */ - -/* Control Register Set 0 */ -static int TC_LSB; /* transfer counter lsb */ -static int TC_MSB; /* transfer counter msb */ -static int SCSI_FIFO; /* scsi fifo register */ -static int CMD_REG; /* command register */ -static int STAT_REG; /* status register */ -static int DEST_ID; /* selection/reselection bus id */ -static int INT_REG; /* interrupt status register */ -static int SRTIMOUT; /* select/reselect timeout reg */ -static int SEQ_REG; /* sequence step register */ -static int SYNCPRD; /* synchronous transfer period */ -static int FIFO_FLAGS; /* indicates # of bytes in fifo */ -static int SYNCOFF; /* synchronous offset register */ -static int CONFIG1; /* configuration register */ -static int CLKCONV; /* clock conversion reg */ - /*static int TESTREG;*//* test mode register */ -static int CONFIG2; /* Configuration 2 Register */ -static int CONFIG3; /* Configuration 3 Register */ -static int CONFIG4; /* Configuration 4 Register */ -static int TC_HIGH; /* Transfer Counter High */ - /*static int FIFO_BOTTOM;*//* Reserve FIFO byte register */ - -/* Control Register Set 1 */ - /*static int JUMPER_SENSE;*//* Jumper sense port reg (r/w) */ - /*static int SRAM_PTR;*//* SRAM address pointer reg (r/w) */ - /*static int SRAM_DATA;*//* SRAM data register (r/w) */ -static int PIO_FIFO; /* PIO FIFO registers (r/w) */ - /*static int PIO_FIFO1;*//* */ - /*static int PIO_FIFO2;*//* */ - /*static int PIO_FIFO3;*//* */ -static int PIO_STATUS; /* PIO status (r/w) */ - /*static int ATA_CMD;*//* ATA command/status reg (r/w) */ - /*static int ATA_ERR;*//* ATA features/error register (r/w) */ -static int PIO_FLAG; /* PIO flag interrupt enable (r/w) */ -static int CONFIG5; /* Configuration 5 register (r/w) */ - /*static int SIGNATURE;*//* Signature Register (r) */ - /*static int CONFIG6;*//* Configuration 6 register (r) */ - -/* ============================================================== */ - -#if USE_DMA -static __inline__ int NCR53c406a_dma_setup(unsigned char *ptr, unsigned int count, unsigned char mode) -{ - unsigned limit; - unsigned long flags = 0; - - VDEB(printk("dma: before count=%d ", count)); - if (dma_chan <= 3) { - if (count > 65536) - count = 65536; - limit = 65536 - (((unsigned) ptr) & 0xFFFF); - } else { - if (count > (65536 << 1)) - count = (65536 << 1); - limit = (65536 << 1) - (((unsigned) ptr) & 0x1FFFF); - } - - if (count > limit) - count = limit; - - VDEB(printk("after count=%d\n", count)); - if ((count & 1) || (((unsigned) ptr) & 1)) - panic("NCR53c406a: attempted unaligned DMA transfer\n"); - - flags = claim_dma_lock(); - disable_dma(dma_chan); - clear_dma_ff(dma_chan); - set_dma_addr(dma_chan, (long) ptr); - set_dma_count(dma_chan, count); - set_dma_mode(dma_chan, mode); - enable_dma(dma_chan); - release_dma_lock(flags); - - return count; -} - -static __inline__ int NCR53c406a_dma_write(unsigned char *src, unsigned int count) -{ - return NCR53c406a_dma_setup(src, count, DMA_MODE_WRITE); -} - -static __inline__ int NCR53c406a_dma_read(unsigned char *src, unsigned int count) -{ - return NCR53c406a_dma_setup(src, count, DMA_MODE_READ); -} - -static __inline__ int NCR53c406a_dma_residual(void) -{ - register int tmp; - unsigned long flags; - - flags = claim_dma_lock(); - clear_dma_ff(dma_chan); - tmp = get_dma_residue(dma_chan); - release_dma_lock(flags); - - return tmp; -} -#endif /* USE_DMA */ - -#if USE_PIO -static __inline__ int NCR53c406a_pio_read(unsigned char *request, unsigned int reqlen) -{ - int i; - int len; /* current scsi fifo size */ - - REG1; - while (reqlen) { - i = inb(PIO_STATUS); - /* VDEB(printk("pio_status=%x\n", i)); */ - if (i & 0x80) - return 0; - - switch (i & 0x1e) { - default: - case 0x10: - len = 0; - break; - case 0x0: - len = 1; - break; - case 0x8: - len = 42; - break; - case 0xc: - len = 84; - break; - case 0xe: - len = 128; - break; - } - - if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */ - return 0; - } - - if (len) { - if (len > reqlen) - len = reqlen; - - if (fast_pio && len > 3) { - insl(PIO_FIFO, request, len >> 2); - request += len & 0xfc; - reqlen -= len & 0xfc; - } else { - while (len--) { - *request++ = inb(PIO_FIFO); - reqlen--; - } - } - } - } - return 0; -} - -static __inline__ int NCR53c406a_pio_write(unsigned char *request, unsigned int reqlen) -{ - int i = 0; - int len; /* current scsi fifo size */ - - REG1; - while (reqlen && !(i & 0x40)) { - i = inb(PIO_STATUS); - /* VDEB(printk("pio_status=%x\n", i)); */ - if (i & 0x80) /* error */ - return 0; - - switch (i & 0x1e) { - case 0x10: - len = 128; - break; - case 0x0: - len = 84; - break; - case 0x8: - len = 42; - break; - case 0xc: - len = 1; - break; - default: - case 0xe: - len = 0; - break; - } - - if (len) { - if (len > reqlen) - len = reqlen; - - if (fast_pio && len > 3) { - outsl(PIO_FIFO, request, len >> 2); - request += len & 0xfc; - reqlen -= len & 0xfc; - } else { - while (len--) { - outb(*request++, PIO_FIFO); - reqlen--; - } - } - } - } - return 0; -} -#endif /* USE_PIO */ - -static int __init NCR53c406a_detect(struct scsi_host_template * tpnt) -{ - int present = 0; - struct Scsi_Host *shpnt = NULL; -#ifndef PORT_BASE - int i; -#endif - -#if USE_BIOS - int ii, jj; - bios_base = 0; - /* look for a valid signature */ - for (ii = 0; ii < ADDRESS_COUNT && !bios_base; ii++) - for (jj = 0; (jj < SIGNATURE_COUNT) && !bios_base; jj++) - if (!memcmp((void *) addresses[ii] + signatures[jj].sig_offset, (void *) signatures[jj].signature, (int) signatures[jj].sig_length)) - bios_base = addresses[ii]; - - if (!bios_base) { - printk("NCR53c406a: BIOS signature not found\n"); - return 0; - } - - DEB(printk("NCR53c406a BIOS found at 0x%x\n", (unsigned int) bios_base); - ); -#endif /* USE_BIOS */ - -#ifdef PORT_BASE - if (!request_region(port_base, 0x10, "NCR53c406a")) /* ports already snatched */ - port_base = 0; - -#else /* autodetect */ - if (port_base) { /* LILO override */ - if (!request_region(port_base, 0x10, "NCR53c406a")) - port_base = 0; - } else { - for (i = 0; i < PORT_COUNT && !port_base; i++) { - if (!request_region(ports[i], 0x10, "NCR53c406a")) { - DEB(printk("NCR53c406a: port 0x%x in use\n", ports[i])); - } else { - VDEB(printk("NCR53c406a: port 0x%x available\n", ports[i])); - outb(C5_IMG, ports[i] + 0x0d); /* reg set 1 */ - if ((inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) & 0xf8) == 0x58) { - port_base = ports[i]; - VDEB(printk("NCR53c406a: Sig register valid\n")); - VDEB(printk("port_base=0x%x\n", port_base)); - break; - } - release_region(ports[i], 0x10); - } - } - } -#endif /* PORT_BASE */ - - if (!port_base) { /* no ports found */ - printk("NCR53c406a: no available ports found\n"); - return 0; - } - - DEB(printk("NCR53c406a detected\n")); - - calc_port_addr(); - chip_init(); - -#ifndef IRQ_LEV - if (irq_level < 0) { /* LILO override if >= 0 */ - irq_level = irq_probe(); - if (irq_level < 0) { /* Trouble */ - printk("NCR53c406a: IRQ problem, irq_level=%d, giving up\n", irq_level); - goto err_release; - } - } -#endif - - DEB(printk("NCR53c406a: using port_base 0x%x\n", port_base)); - - present = 1; - tpnt->proc_name = "NCR53c406a"; - - shpnt = scsi_register(tpnt, 0); - if (!shpnt) { - printk("NCR53c406a: Unable to register host, giving up.\n"); - goto err_release; - } - - if (irq_level > 0) { - if (request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", shpnt)) { - printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level); - goto err_free_scsi; - } - tpnt->can_queue = 1; - DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level)); - } else if (irq_level == 0) { - tpnt->can_queue = 0; - DEB(printk("NCR53c406a: No interrupts detected\n")); - printk("NCR53c406a driver no longer supports polling interface\n"); - printk("Please email linux-scsi@vger.kernel.org\n"); - -#if USE_DMA - printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n"); -#endif /* USE_DMA */ - goto err_free_scsi; - } else { - DEB(printk("NCR53c406a: Shouldn't get here!\n")); - goto err_free_scsi; - } - -#if USE_DMA - dma_chan = DMA_CHAN; - if (request_dma(dma_chan, "NCR53c406a") != 0) { - printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan); - goto err_free_irq; - } - - DEB(printk("Allocated DMA channel %d\n", dma_chan)); -#endif /* USE_DMA */ - - shpnt->irq = irq_level; - shpnt->io_port = port_base; - shpnt->n_io_port = 0x10; -#if USE_DMA - shpnt->dma = dma_chan; -#endif - -#if USE_DMA - sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, DMA channel %d.", port_base, irq_level, dma_chan); -#else - sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, %s PIO mode.", port_base, irq_level, fast_pio ? "fast" : "slow"); -#endif - - return (present); - -#if USE_DMA - err_free_irq: - if (irq_level) - free_irq(irq_level, shpnt); -#endif - err_free_scsi: - scsi_unregister(shpnt); - err_release: - release_region(port_base, 0x10); - return 0; -} - -static int NCR53c406a_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); -#if USE_DMA - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); -#endif - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - - scsi_unregister(shost); - return 0; -} - -#ifndef MODULE -/* called from init/main.c */ -static int __init NCR53c406a_setup(char *str) -{ - static size_t setup_idx = 0; - size_t i; - int ints[4]; - - DEB(printk("NCR53c406a: Setup called\n"); - ); - - if (setup_idx >= PORT_COUNT - 1) { - printk("NCR53c406a: Setup called too many times. Bad LILO params?\n"); - return 0; - } - get_options(str, 4, ints); - if (ints[0] < 1 || ints[0] > 3) { - printk("NCR53c406a: Malformed command line\n"); - printk("NCR53c406a: Usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]\n"); - return 0; - } - for (i = 0; i < PORT_COUNT && !port_base; i++) - if (ports[i] == ints[1]) { - port_base = ints[1]; - DEB(printk("NCR53c406a: Specified port_base 0x%x\n", port_base); - ) - } - if (!port_base) { - printk("NCR53c406a: Invalid PORTBASE 0x%x specified\n", ints[1]); - return 0; - } - - if (ints[0] > 1) { - if (ints[2] == 0) { - irq_level = 0; - DEB(printk("NCR53c406a: Specified irq %d\n", irq_level); - ) - } else - for (i = 0; i < INTR_COUNT && irq_level < 0; i++) - if (intrs[i] == ints[2]) { - irq_level = ints[2]; - DEB(printk("NCR53c406a: Specified irq %d\n", port_base); - ) - } - if (irq_level < 0) - printk("NCR53c406a: Invalid IRQ %d specified\n", ints[2]); - } - - if (ints[0] > 2) - fast_pio = ints[3]; - - DEB(printk("NCR53c406a: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, fast_pio);) - return 1; -} - -__setup("ncr53c406a=", NCR53c406a_setup); - -#endif /* !MODULE */ - -static const char *NCR53c406a_info(struct Scsi_Host *SChost) -{ - DEB(printk("NCR53c406a_info called\n")); - return (info_msg); -} - -#if 0 -static void wait_intr(void) -{ - unsigned long i = jiffies + WATCHDOG; - - while (time_after(i, jiffies) && !(inb(STAT_REG) & 0xe0)) { /* wait for a pseudo-interrupt */ - cpu_relax(); - barrier(); - } - - if (time_before_eq(i, jiffies)) { /* Timed out */ - rtrc(0); - current_SC->result = DID_TIME_OUT << 16; - current_SC->SCp.phase = idle; - current_SC->scsi_done(current_SC); - return; - } - - NCR53c406a_intr(NULL); -} -#endif - -static int NCR53c406a_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) -{ - int i; - - VDEB(printk("NCR53c406a_queue called\n")); - DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->target, (u8)SCpnt->device->lun, scsi_bufflen(SCpnt))); - -#if 0 - VDEB(for (i = 0; i < SCpnt->cmd_len; i++) - printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); - VDEB(printk("\n")); -#endif - - current_SC = SCpnt; - current_SC->scsi_done = done; - current_SC->SCp.phase = command_ph; - current_SC->SCp.Status = 0; - current_SC->SCp.Message = 0; - - /* We are locked here already by the mid layer */ - REG0; - outb(scmd_id(SCpnt), DEST_ID); /* set destination */ - outb(FLUSH_FIFO, CMD_REG); /* reset the fifos */ - - for (i = 0; i < SCpnt->cmd_len; i++) { - outb(SCpnt->cmnd[i], SCSI_FIFO); - } - outb(SELECT_NO_ATN, CMD_REG); - - rtrc(1); - return 0; -} - -static DEF_SCSI_QCMD(NCR53c406a_queue) - -static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt) -{ - DEB(printk("NCR53c406a_reset called\n")); - - spin_lock_irq(SCpnt->device->host->host_lock); - - outb(C4_IMG, CONFIG4); /* Select reg set 0 */ - outb(CHIP_RESET, CMD_REG); - outb(SCSI_NOP, CMD_REG); /* required after reset */ - outb(SCSI_RESET, CMD_REG); - chip_init(); - - rtrc(2); - - spin_unlock_irq(SCpnt->device->host->host_lock); - - return SUCCESS; -} - -static int NCR53c406a_biosparm(struct scsi_device *disk, - struct block_device *dev, - sector_t capacity, int *info_array) -{ - int size; - - DEB(printk("NCR53c406a_biosparm called\n")); - - size = capacity; - info_array[0] = 64; /* heads */ - info_array[1] = 32; /* sectors */ - info_array[2] = size >> 11; /* cylinders */ - if (info_array[2] > 1024) { /* big disk */ - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = size / (255 * 63); - } - return 0; -} - -static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); - NCR53c406a_intr(dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -static void NCR53c406a_intr(void *dev_id) -{ - DEB(unsigned char fifo_size; - ) - DEB(unsigned char seq_reg; - ) - unsigned char status, int_reg; -#if USE_PIO - unsigned char pio_status; - struct scatterlist *sg; - int i; -#endif - - VDEB(printk("NCR53c406a_intr called\n")); - -#if USE_PIO - REG1; - pio_status = inb(PIO_STATUS); -#endif - REG0; - status = inb(STAT_REG); - DEB(seq_reg = inb(SEQ_REG)); - int_reg = inb(INT_REG); - DEB(fifo_size = inb(FIFO_FLAGS) & 0x1f); - -#if NCR53C406A_DEBUG - printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", status, seq_reg, int_reg, fifo_size); -#if (USE_DMA) - printk("\n"); -#else - printk(", pio=%02x\n", pio_status); -#endif /* USE_DMA */ -#endif /* NCR53C406A_DEBUG */ - - if (int_reg & 0x80) { /* SCSI reset intr */ - rtrc(3); - DEB(printk("NCR53c406a: reset intr received\n")); - current_SC->SCp.phase = idle; - current_SC->result = DID_RESET << 16; - current_SC->scsi_done(current_SC); - return; - } -#if USE_PIO - if (pio_status & 0x80) { - printk("NCR53C406A: Warning: PIO error!\n"); - current_SC->SCp.phase = idle; - current_SC->result = DID_ERROR << 16; - current_SC->scsi_done(current_SC); - return; - } -#endif /* USE_PIO */ - - if (status & 0x20) { /* Parity error */ - printk("NCR53c406a: Warning: parity error!\n"); - current_SC->SCp.phase = idle; - current_SC->result = DID_PARITY << 16; - current_SC->scsi_done(current_SC); - return; - } - - if (status & 0x40) { /* Gross error */ - printk("NCR53c406a: Warning: gross error!\n"); - current_SC->SCp.phase = idle; - current_SC->result = DID_ERROR << 16; - current_SC->scsi_done(current_SC); - return; - } - - if (int_reg & 0x20) { /* Disconnect */ - DEB(printk("NCR53c406a: disconnect intr received\n")); - if (current_SC->SCp.phase != message_in) { /* Unexpected disconnect */ - current_SC->result = DID_NO_CONNECT << 16; - } else { /* Command complete, return status and message */ - current_SC->result = (current_SC->SCp.Status & 0xff) - | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16); - } - - rtrc(0); - current_SC->SCp.phase = idle; - current_SC->scsi_done(current_SC); - return; - } - - switch (status & 0x07) { /* scsi phase */ - case 0x00: /* DATA-OUT */ - if (int_reg & 0x10) { /* Target requesting info transfer */ - rtrc(5); - current_SC->SCp.phase = data_out; - VDEB(printk("NCR53c406a: Data-Out phase\n")); - outb(FLUSH_FIFO, CMD_REG); - LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */ -#if USE_DMA /* No s/g support for DMA */ - NCR53c406a_dma_write(scsi_sglist(current_SC), - scsdi_bufflen(current_SC)); - -#endif /* USE_DMA */ - outb(TRANSFER_INFO | DMA_OP, CMD_REG); -#if USE_PIO - scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) { - NCR53c406a_pio_write(sg_virt(sg), sg->length); - } - REG0; -#endif /* USE_PIO */ - } - break; - - case 0x01: /* DATA-IN */ - if (int_reg & 0x10) { /* Target requesting info transfer */ - rtrc(6); - current_SC->SCp.phase = data_in; - VDEB(printk("NCR53c406a: Data-In phase\n")); - outb(FLUSH_FIFO, CMD_REG); - LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */ -#if USE_DMA /* No s/g support for DMA */ - NCR53c406a_dma_read(scsi_sglist(current_SC), - scsdi_bufflen(current_SC)); -#endif /* USE_DMA */ - outb(TRANSFER_INFO | DMA_OP, CMD_REG); -#if USE_PIO - scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) { - NCR53c406a_pio_read(sg_virt(sg), sg->length); - } - REG0; -#endif /* USE_PIO */ - } - break; - - case 0x02: /* COMMAND */ - current_SC->SCp.phase = command_ph; - printk("NCR53c406a: Warning: Unknown interrupt occurred in command phase!\n"); - break; - - case 0x03: /* STATUS */ - rtrc(7); - current_SC->SCp.phase = status_ph; - VDEB(printk("NCR53c406a: Status phase\n")); - outb(FLUSH_FIFO, CMD_REG); - outb(INIT_CMD_COMPLETE, CMD_REG); - break; - - case 0x04: /* Reserved */ - case 0x05: /* Reserved */ - printk("NCR53c406a: WARNING: Reserved phase!!!\n"); - break; - - case 0x06: /* MESSAGE-OUT */ - DEB(printk("NCR53c406a: Message-Out phase\n")); - current_SC->SCp.phase = message_out; - outb(SET_ATN, CMD_REG); /* Reject the message */ - outb(MSG_ACCEPT, CMD_REG); - break; - - case 0x07: /* MESSAGE-IN */ - rtrc(4); - VDEB(printk("NCR53c406a: Message-In phase\n")); - current_SC->SCp.phase = message_in; - - current_SC->SCp.Status = inb(SCSI_FIFO); - current_SC->SCp.Message = inb(SCSI_FIFO); - - VDEB(printk("SCSI FIFO size=%d\n", inb(FIFO_FLAGS) & 0x1f)); - DEB(printk("Status = %02x Message = %02x\n", current_SC->SCp.Status, current_SC->SCp.Message)); - - if (current_SC->SCp.Message == SAVE_POINTERS || current_SC->SCp.Message == DISCONNECT) { - outb(SET_ATN, CMD_REG); /* Reject message */ - DEB(printk("Discarding SAVE_POINTERS message\n")); - } - outb(MSG_ACCEPT, CMD_REG); - break; - } -} - -#ifndef IRQ_LEV -static int irq_probe(void) -{ - int irqs, irq; - unsigned long i; - - inb(INT_REG); /* clear the interrupt register */ - irqs = probe_irq_on(); - - /* Invalid command will cause an interrupt */ - REG0; - outb(0xff, CMD_REG); - - /* Wait for the interrupt to occur */ - i = jiffies + WATCHDOG; - while (time_after(i, jiffies) && !(inb(STAT_REG) & 0x80)) - barrier(); - if (time_before_eq(i, jiffies)) { /* Timed out, must be hardware trouble */ - probe_irq_off(irqs); - return -1; - } - - irq = probe_irq_off(irqs); - - /* Kick the chip */ - outb(CHIP_RESET, CMD_REG); - outb(SCSI_NOP, CMD_REG); - chip_init(); - - return irq; -} -#endif /* IRQ_LEV */ - -static void chip_init(void) -{ - REG1; -#if USE_DMA - outb(0x00, PIO_STATUS); -#else /* USE_PIO */ - outb(0x01, PIO_STATUS); -#endif - outb(0x00, PIO_FLAG); - - outb(C4_IMG, CONFIG4); /* REG0; */ - outb(C3_IMG, CONFIG3); - outb(C2_IMG, CONFIG2); - outb(C1_IMG, CONFIG1); - - outb(0x05, CLKCONV); /* clock conversion factor */ - outb(0x9C, SRTIMOUT); /* Selection timeout */ - outb(0x05, SYNCPRD); /* Synchronous transfer period */ - outb(SYNC_MODE, SYNCOFF); /* synchronous mode */ -} - -static void __init calc_port_addr(void) -{ - /* Control Register Set 0 */ - TC_LSB = (port_base + 0x00); - TC_MSB = (port_base + 0x01); - SCSI_FIFO = (port_base + 0x02); - CMD_REG = (port_base + 0x03); - STAT_REG = (port_base + 0x04); - DEST_ID = (port_base + 0x04); - INT_REG = (port_base + 0x05); - SRTIMOUT = (port_base + 0x05); - SEQ_REG = (port_base + 0x06); - SYNCPRD = (port_base + 0x06); - FIFO_FLAGS = (port_base + 0x07); - SYNCOFF = (port_base + 0x07); - CONFIG1 = (port_base + 0x08); - CLKCONV = (port_base + 0x09); - /* TESTREG = (port_base+0x0A); */ - CONFIG2 = (port_base + 0x0B); - CONFIG3 = (port_base + 0x0C); - CONFIG4 = (port_base + 0x0D); - TC_HIGH = (port_base + 0x0E); - /* FIFO_BOTTOM = (port_base+0x0F); */ - - /* Control Register Set 1 */ - /* JUMPER_SENSE = (port_base+0x00); */ - /* SRAM_PTR = (port_base+0x01); */ - /* SRAM_DATA = (port_base+0x02); */ - PIO_FIFO = (port_base + 0x04); - /* PIO_FIFO1 = (port_base+0x05); */ - /* PIO_FIFO2 = (port_base+0x06); */ - /* PIO_FIFO3 = (port_base+0x07); */ - PIO_STATUS = (port_base + 0x08); - /* ATA_CMD = (port_base+0x09); */ - /* ATA_ERR = (port_base+0x0A); */ - PIO_FLAG = (port_base + 0x0B); - CONFIG5 = (port_base + 0x0D); - /* SIGNATURE = (port_base+0x0E); */ - /* CONFIG6 = (port_base+0x0F); */ -} - -MODULE_LICENSE("GPL"); - -/* NOTE: scatter-gather support only works in PIO mode. - * Use SG_NONE if DMA mode is enabled! - */ - -static struct scsi_host_template driver_template = -{ - .proc_name = "NCR53c406a" /* proc_name */, - .name = "NCR53c406a" /* name */, - .detect = NCR53c406a_detect /* detect */, - .release = NCR53c406a_release, - .info = NCR53c406a_info /* info */, - .queuecommand = NCR53c406a_queue /* queuecommand */, - .eh_host_reset_handler = NCR53c406a_host_reset /* reset */, - .bios_param = NCR53c406a_biosparm /* biosparm */, - .can_queue = 1 /* can_queue */, - .this_id = 7 /* SCSI ID of the chip */, - .sg_tablesize = 32 /*SG_ALL*/ /*SG_NONE*/, - .unchecked_isa_dma = 1 /* unchecked_isa_dma */, - .use_clustering = ENABLE_CLUSTERING, -}; - -#include "scsi_module.c" - -/* - * Overrides for Emacs so that we get a uniform tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 0095fcbd1c88..29bf1e60f542 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1231,6 +1231,7 @@ struct src_registers { #define SRC_ODR_SHIFT 12 #define SRC_IDR_SHIFT 9 +#define SRC_MSI_READ_MASK 0x1000 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); @@ -1528,6 +1529,7 @@ struct aac_bus_info_response { #define AAC_COMM_MESSAGE_TYPE3 5 #define AAC_EXTOPT_SA_FIRMWARE cpu_to_le32(1<<1) +#define AAC_EXTOPT_SOFT_RESET cpu_to_le32(1<<16) /* MSIX context */ struct aac_msix_ctx { @@ -1662,6 +1664,7 @@ struct aac_dev u8 raw_io_64; u8 printf_enabled; u8 in_reset; + u8 in_soft_reset; u8 msi; u8 sa_firmware; int management_fib_count; @@ -2504,6 +2507,7 @@ struct aac_hba_info { #define RCV_TEMP_READINGS 0x00000025 #define GET_COMM_PREFERRED_SETTINGS 0x00000026 #define IOP_RESET_FW_FIB_DUMP 0x00000034 +#define DROP_IO 0x00000035 #define IOP_RESET 0x00001000 #define IOP_RESET_ALWAYS 0x00001001 #define RE_INIT_ADAPTER 0x000000ee @@ -2539,6 +2543,7 @@ struct aac_hba_info { #define FLASH_UPD_PENDING 0x00002000 #define FLASH_UPD_SUCCESS 0x00004000 #define FLASH_UPD_FAILED 0x00008000 +#define INVALID_OMR 0xffffffff #define FWUPD_TIMEOUT (5 * 60) /* diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index a802bddf04aa..4ebb35a29caa 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -255,7 +255,8 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command, */ src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); - if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) { + if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) && + !dev->in_soft_reset) { ok = 0; start = jiffies; @@ -679,6 +680,25 @@ void aac_set_intx_mode(struct aac_dev *dev) } } +static void aac_clear_omr(struct aac_dev *dev) +{ + u32 omr_value = 0; + + omr_value = src_readl(dev, MUnit.OMR); + + /* + * Check for PCI Errors or Kernel Panic + */ + if ((omr_value == INVALID_OMR) || (omr_value & KERNEL_PANIC)) + omr_value = 0; + + /* + * Preserve MSIX Value if any + */ + src_writel(dev, MUnit.OMR, omr_value & AAC_INT_MODE_MSIX); + src_readl(dev, MUnit.OMR); +} + static void aac_dump_fw_fib_iop_reset(struct aac_dev *dev) { __le32 supported_options3; @@ -739,6 +759,8 @@ static void aac_send_iop_reset(struct aac_dev *dev) aac_set_intx_mode(dev); + aac_clear_omr(dev); + src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK); msleep(5000); @@ -748,6 +770,7 @@ static void aac_send_hardware_soft_reset(struct aac_dev *dev) { u_int32_t val; + aac_clear_omr(dev); val = readl(((char *)(dev->base) + IBW_SWR_OFFSET)); val |= 0x01; writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET)); @@ -992,6 +1015,148 @@ error_iounmap: return -1; } +static int aac_src_wait_sync(struct aac_dev *dev, int *status) +{ + unsigned long start = jiffies; + unsigned long usecs = 0; + int delay = 5 * HZ; + int rc = 1; + + while (time_before(jiffies, start+delay)) { + /* + * Delay 5 microseconds to let Mon960 get info. + */ + udelay(5); + + /* + * Mon960 will set doorbell0 bit when it has completed the + * command. + */ + if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { + /* + * Clear: the doorbell. + */ + if (dev->msi_enabled) + aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT); + else + src_writel(dev, MUnit.ODR_C, + OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); + rc = 0; + + break; + } + + /* + * Yield the processor in case we are slow + */ + usecs = 1 * USEC_PER_MSEC; + usleep_range(usecs, usecs + 50); + } + /* + * Pull the synch status from Mailbox 0. + */ + if (status && !rc) { + status[0] = readl(&dev->IndexRegs->Mailbox[0]); + status[1] = readl(&dev->IndexRegs->Mailbox[1]); + status[2] = readl(&dev->IndexRegs->Mailbox[2]); + status[3] = readl(&dev->IndexRegs->Mailbox[3]); + status[4] = readl(&dev->IndexRegs->Mailbox[4]); + } + + return rc; +} + +/** + * aac_src_soft_reset - perform soft reset to speed up + * access + * + * Assumptions: That the controller is in a state where we can + * bring it back to life with an init struct. We can only use + * fast sync commands, as the timeout is 5 seconds. + * + * @dev: device to configure + * + */ + +static int aac_src_soft_reset(struct aac_dev *dev) +{ + u32 status_omr = src_readl(dev, MUnit.OMR); + u32 status[5]; + int rc = 1; + int state = 0; + char *state_str[7] = { + "GET_ADAPTER_PROPERTIES Failed", + "GET_ADAPTER_PROPERTIES timeout", + "SOFT_RESET not supported", + "DROP_IO Failed", + "DROP_IO timeout", + "Check Health failed" + }; + + if (status_omr == INVALID_OMR) + return 1; // pcie hosed + + if (!(status_omr & KERNEL_UP_AND_RUNNING)) + return 1; // not up and running + + /* + * We go into soft reset mode to allow us to handle response + */ + dev->in_soft_reset = 1; + dev->msi_enabled = status_omr & AAC_INT_MODE_MSIX; + + /* Get adapter properties */ + rc = aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, + 0, 0, 0, status+0, status+1, status+2, status+3, status+4); + if (rc) + goto out; + + state++; + if (aac_src_wait_sync(dev, status)) { + rc = 1; + goto out; + } + + state++; + if (!(status[1] & le32_to_cpu(AAC_OPT_EXTENDED) && + (status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)))) { + rc = 2; + goto out; + } + + if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) && + (status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE))) + dev->sa_firmware = 1; + + state++; + rc = aac_adapter_sync_cmd(dev, DROP_IO, 0, 0, 0, 0, 0, 0, + status+0, status+1, status+2, status+3, status+4); + + if (rc) + goto out; + + state++; + if (aac_src_wait_sync(dev, status)) { + rc = 3; + goto out; + } + + if (status[1]) + dev_err(&dev->pdev->dev, "%s: %d outstanding I/O pending\n", + __func__, status[1]); + + state++; + rc = aac_src_check_health(dev); + +out: + dev->in_soft_reset = 0; + dev->msi_enabled = 0; + if (rc) + dev_err(&dev->pdev->dev, "%s: %s status = %d", __func__, + state_str[state], rc); + +return rc; +} /** * aac_srcv_init - initialize an SRCv card * @dev: device to configure @@ -1021,8 +1186,10 @@ int aac_srcv_init(struct aac_dev *dev) if (dev->init_reset) { dev->init_reset = false; - if (!aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) + if (aac_src_soft_reset(dev)) { + aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET); ++restart; + } } /* @@ -1072,13 +1239,16 @@ int aac_srcv_init(struct aac_dev *dev) printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); goto error_iounmap; } + start = jiffies; /* * Wait for the adapter to be up and running. Wait up to 3 minutes */ - while (!((status = src_readl(dev, MUnit.OMR)) & - KERNEL_UP_AND_RUNNING) || - status == 0xffffffff) { + do { + status = src_readl(dev, MUnit.OMR); + if (status == INVALID_OMR) + status = 0; + if ((restart && (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || time_after(jiffies, start+HZ*startup_timeout)) { @@ -1098,7 +1268,8 @@ int aac_srcv_init(struct aac_dev *dev) ++restart; } msleep(1); - } + } while (!(status & KERNEL_UP_AND_RUNNING)); + if (restart && aac_commit) aac_commit = 1; /* @@ -1234,13 +1405,23 @@ void aac_src_access_devreg(struct aac_dev *dev, int mode) static int aac_src_get_sync_status(struct aac_dev *dev) { + int msix_val = 0; + int legacy_val = 0; - int val; + msix_val = src_readl(dev, MUnit.ODR_MSI) & SRC_MSI_READ_MASK ? 1 : 0; - if (dev->msi_enabled) - val = src_readl(dev, MUnit.ODR_MSI) & 0x1000 ? 1 : 0; - else - val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT; + if (!dev->msi_enabled) { + /* + * if Legacy int status indicates cmd is not complete + * sample MSIx register to see if it indiactes cmd complete, + * if yes set the controller in MSIx mode and consider cmd + * completed + */ + legacy_val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT; + if (!(legacy_val & 1) && msix_val) + dev->msi_enabled = 1; + return legacy_val; + } - return val; + return msix_val; } diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index bad35ffc015d..b48d5436f094 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -592,7 +592,7 @@ static int aha1740_probe (struct device *dev) DMA_BIDIRECTIONAL); if (!host->ecb_dma_addr) { printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n"); - scsi_unregister (shpnt); + scsi_host_put (shpnt); goto err_host_put; } diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index b560f396ee99..034f4eebb160 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -9338,9 +9338,9 @@ ahd_dumpseq(struct ahd_softc* ahd) static void ahd_loadseq(struct ahd_softc *ahd) { - struct cs cs_table[num_critical_sections]; - u_int begin_set[num_critical_sections]; - u_int end_set[num_critical_sections]; + struct cs cs_table[NUM_CRITICAL_SECTIONS]; + u_int begin_set[NUM_CRITICAL_SECTIONS]; + u_int end_set[NUM_CRITICAL_SECTIONS]; const struct patch *cur_patch; u_int cs_count; u_int cur_cs; @@ -9456,7 +9456,7 @@ ahd_loadseq(struct ahd_softc *ahd) * Move through the CS table until we find a CS * that might apply to this instruction. */ - for (; cur_cs < num_critical_sections; cur_cs++) { + for (; cur_cs < NUM_CRITICAL_SECTIONS; cur_cs++) { if (critical_sections[cur_cs].end <= i) { if (begin_set[cs_count] == TRUE && end_set[cs_count] == FALSE) { diff --git a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped index 4b51e232392f..fd64a950ee44 100644 --- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped @@ -1186,5 +1186,4 @@ static const struct cs { { 759, 763 } }; -static const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections); +#define NUM_CRITICAL_SECTIONS ARRAY_SIZE(critical_sections) diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 6612ff3b2e83..e97eceacf522 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -6848,9 +6848,9 @@ ahc_dumpseq(struct ahc_softc* ahc) static int ahc_loadseq(struct ahc_softc *ahc) { - struct cs cs_table[num_critical_sections]; - u_int begin_set[num_critical_sections]; - u_int end_set[num_critical_sections]; + struct cs cs_table[NUM_CRITICAL_SECTIONS]; + u_int begin_set[NUM_CRITICAL_SECTIONS]; + u_int end_set[NUM_CRITICAL_SECTIONS]; const struct patch *cur_patch; u_int cs_count; u_int cur_cs; @@ -6915,7 +6915,7 @@ ahc_loadseq(struct ahc_softc *ahc) * Move through the CS table until we find a CS * that might apply to this instruction. */ - for (; cur_cs < num_critical_sections; cur_cs++) { + for (; cur_cs < NUM_CRITICAL_SECTIONS; cur_cs++) { if (critical_sections[cur_cs].end <= i) { if (begin_set[cs_count] == TRUE && end_set[cs_count] == FALSE) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped index 07e93fbae706..f37362bc8ece 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped @@ -1304,5 +1304,4 @@ static const struct cs { { 875, 877 } }; -static const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections); +#define NUM_CRITICAL_SECTIONS ARRAY_SIZE(critical_sections) diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c index 21ac265280bf..5f474e490f3e 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c @@ -451,8 +451,7 @@ output_code() fprintf(ofile, "\n};\n\n"); fprintf(ofile, -"static const int num_critical_sections = sizeof(critical_sections)\n" -" / sizeof(*critical_sections);\n"); + "#define NUM_CRITICAL_SECTIONS ARRAY_SIZE(critical_sections)\n"); fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); } diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index f375f3557c18..2e51ccc510e8 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -49,7 +49,7 @@ struct device_attribute; #define ARCMSR_MAX_OUTSTANDING_CMD 1024 #define ARCMSR_DEFAULT_OUTSTANDING_CMD 128 #define ARCMSR_MIN_OUTSTANDING_CMD 32 -#define ARCMSR_DRIVER_VERSION "v1.40.00.04-20171130" +#define ARCMSR_DRIVER_VERSION "v1.40.00.05-20180309" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -779,12 +779,12 @@ struct AdapterControlBlock /* message clear rqbuffer */ #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 #define ACB_F_BUS_RESET 0x0080 -#define ACB_F_BUS_HANG_ON 0x0800/* need hardware reset bus */ #define ACB_F_IOP_INITED 0x0100 /* iop init */ #define ACB_F_ABORT 0x0200 #define ACB_F_FIRMWARE_TRAP 0x0400 +#define ACB_F_ADAPTER_REMOVED 0x0800 #define ACB_F_MSG_GET_CONFIG 0x1000 struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 75e828bd30e3..732b5d9242f1 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1446,12 +1446,80 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) } } +static void arcmsr_remove_scsi_devices(struct AdapterControlBlock *acb) +{ + char *acb_dev_map = (char *)acb->device_map; + int target, lun, i; + struct scsi_device *psdev; + struct CommandControlBlock *ccb; + char temp; + + for (i = 0; i < acb->maxFreeCCB; i++) { + ccb = acb->pccb_pool[i]; + if (ccb->startdone == ARCMSR_CCB_START) { + ccb->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_pci_unmap_dma(ccb); + ccb->pcmd->scsi_done(ccb->pcmd); + } + } + for (target = 0; target < ARCMSR_MAX_TARGETID; target++) { + temp = *acb_dev_map; + if (temp) { + for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { + if (temp & 1) { + psdev = scsi_device_lookup(acb->host, + 0, target, lun); + if (psdev != NULL) { + scsi_remove_device(psdev); + scsi_device_put(psdev); + } + } + temp >>= 1; + } + *acb_dev_map = 0; + } + acb_dev_map++; + } +} + +static void arcmsr_free_pcidev(struct AdapterControlBlock *acb) +{ + struct pci_dev *pdev; + struct Scsi_Host *host; + + host = acb->host; + arcmsr_free_sysfs_attr(acb); + scsi_remove_host(host); + flush_work(&acb->arcmsr_do_message_isr_bh); + del_timer_sync(&acb->eternal_timer); + if (set_date_time) + del_timer_sync(&acb->refresh_timer); + pdev = acb->pdev; + arcmsr_free_irq(pdev, acb); + arcmsr_free_ccb_pool(acb); + arcmsr_free_mu(acb); + arcmsr_unmap_pciregion(acb); + pci_release_regions(pdev); + scsi_host_put(host); + pci_disable_device(pdev); +} + static void arcmsr_remove(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; int poll_count = 0; + uint16_t dev_id; + + pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); + if (dev_id == 0xffff) { + acb->acb_flags &= ~ACB_F_IOP_INITED; + acb->acb_flags |= ACB_F_ADAPTER_REMOVED; + arcmsr_remove_scsi_devices(acb); + arcmsr_free_pcidev(acb); + return; + } arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); flush_work(&acb->arcmsr_do_message_isr_bh); @@ -1499,6 +1567,8 @@ static void arcmsr_shutdown(struct pci_dev *pdev) struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; + if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) + return; del_timer_sync(&acb->eternal_timer); if (set_date_time) del_timer_sync(&acb->refresh_timer); @@ -2931,6 +3001,12 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; struct CommandControlBlock *ccb; int target = cmd->device->id; + + if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) { + cmd->result = (DID_NO_CONNECT << 16); + cmd->scsi_done(cmd); + return 0; + } cmd->scsi_done = done; cmd->host_scribble = NULL; cmd->result = 0; @@ -3731,6 +3807,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; do { + if (!(acb->acb_flags & ACB_F_IOP_INITED)) + msleep(20); firmware_state = readl(®->outbound_msgaddr1); } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); } @@ -3739,6 +3817,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; do { + if (!(acb->acb_flags & ACB_F_IOP_INITED)) + msleep(20); firmware_state = readl(reg->iop2drv_doorbell); } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); @@ -3747,6 +3827,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_C: { struct MessageUnit_C __iomem *reg = acb->pmuC; do { + if (!(acb->acb_flags & ACB_F_IOP_INITED)) + msleep(20); firmware_state = readl(®->outbound_msgaddr1); } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); } @@ -3754,6 +3836,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_D: { struct MessageUnit_D *reg = acb->pmuD; do { + if (!(acb->acb_flags & ACB_F_IOP_INITED)) + msleep(20); firmware_state = readl(reg->outbound_msgaddr1); } while ((firmware_state & ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0); @@ -3762,6 +3846,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_E: { struct MessageUnit_E __iomem *reg = acb->pmuE; do { + if (!(acb->acb_flags & ACB_F_IOP_INITED)) + msleep(20); firmware_state = readl(®->outbound_msgaddr1); } while ((firmware_state & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0); } @@ -4177,6 +4263,8 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) int retry_count = 0; int rtn = FAILED; acb = (struct AdapterControlBlock *) cmd->device->host->hostdata; + if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) + return SUCCESS; pr_notice("arcmsr: executing bus reset eh.....num_resets = %d," " num_aborts = %d \n", acb->num_resets, acb->num_aborts); acb->num_resets++; @@ -4243,6 +4331,8 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) int rtn = FAILED; uint32_t intmask_org; + if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) + return SUCCESS; printk(KERN_NOTICE "arcmsr%d: abort device command of scsi id = %d lun = %d\n", acb->host->host_no, cmd->device->id, (u32)cmd->device->lun); diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 8b52a9dbb9cf..b46997cf77e2 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1413,11 +1413,11 @@ static void atp885_init(struct Scsi_Host *shpnt) atpdev->global_map[m] = 0; for (k = 0; k < 4; k++) { atp_writew_base(atpdev, 0x3c, n++); - ((unsigned long *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38); + ((u32 *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38); } for (k = 0; k < 4; k++) { atp_writew_base(atpdev, 0x3c, n++); - ((unsigned long *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38); + ((u32 *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38); } n += 8; } diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 3976e787ba64..7c884f881180 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -891,7 +891,7 @@ bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd, if (bfad_chk_iocmd_sz(payload_len, sizeof(struct bfa_bsg_fabric_get_lports_s), - sizeof(wwn_t[iocmd->nports])) != BFA_STATUS_OK) { + sizeof(wwn_t) * iocmd->nports) != BFA_STATUS_OK) { iocmd->status = BFA_STATUS_VERSION_FAIL; goto out; } diff --git a/drivers/scsi/csiostor/csio_attr.c b/drivers/scsi/csiostor/csio_attr.c index 2d1c4ebd40f9..8a004036e3d7 100644 --- a/drivers/scsi/csiostor/csio_attr.c +++ b/drivers/scsi/csiostor/csio_attr.c @@ -274,12 +274,24 @@ csio_get_host_speed(struct Scsi_Host *shost) spin_lock_irq(&hw->lock); switch (hw->pport[ln->portid].link_speed) { - case FW_PORT_CAP_SPEED_1G: + case FW_PORT_CAP32_SPEED_1G: fc_host_speed(shost) = FC_PORTSPEED_1GBIT; break; - case FW_PORT_CAP_SPEED_10G: + case FW_PORT_CAP32_SPEED_10G: fc_host_speed(shost) = FC_PORTSPEED_10GBIT; break; + case FW_PORT_CAP32_SPEED_25G: + fc_host_speed(shost) = FC_PORTSPEED_25GBIT; + break; + case FW_PORT_CAP32_SPEED_40G: + fc_host_speed(shost) = FC_PORTSPEED_40GBIT; + break; + case FW_PORT_CAP32_SPEED_50G: + fc_host_speed(shost) = FC_PORTSPEED_50GBIT; + break; + case FW_PORT_CAP32_SPEED_100G: + fc_host_speed(shost) = FC_PORTSPEED_100GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index 0bd1131b6cc9..96bbb82c826d 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -1409,6 +1409,235 @@ out: return rv; } +static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec) +{ + enum cc_fec cc_fec = 0; + + if (fw_fec & FW_PORT_CAP32_FEC_RS) + cc_fec |= FEC_RS; + if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS) + cc_fec |= FEC_BASER_RS; + + return cc_fec; +} + +static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause) +{ + fw_port_cap32_t fw_pause = 0; + + if (cc_pause & PAUSE_RX) + fw_pause |= FW_PORT_CAP32_FC_RX; + if (cc_pause & PAUSE_TX) + fw_pause |= FW_PORT_CAP32_FC_TX; + + return fw_pause; +} + +static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec) +{ + fw_port_cap32_t fw_fec = 0; + + if (cc_fec & FEC_RS) + fw_fec |= FW_PORT_CAP32_FEC_RS; + if (cc_fec & FEC_BASER_RS) + fw_fec |= FW_PORT_CAP32_FEC_BASER_RS; + + return fw_fec; +} + +/** + * fwcap_to_fwspeed - return highest speed in Port Capabilities + * @acaps: advertised Port Capabilities + * + * Get the highest speed for the port from the advertised Port + * Capabilities. + */ +fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps) +{ + #define TEST_SPEED_RETURN(__caps_speed) \ + do { \ + if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \ + return FW_PORT_CAP32_SPEED_##__caps_speed; \ + } while (0) + + TEST_SPEED_RETURN(400G); + TEST_SPEED_RETURN(200G); + TEST_SPEED_RETURN(100G); + TEST_SPEED_RETURN(50G); + TEST_SPEED_RETURN(40G); + TEST_SPEED_RETURN(25G); + TEST_SPEED_RETURN(10G); + TEST_SPEED_RETURN(1G); + TEST_SPEED_RETURN(100M); + + #undef TEST_SPEED_RETURN + + return 0; +} + +/** + * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits + * @caps16: a 16-bit Port Capabilities value + * + * Returns the equivalent 32-bit Port Capabilities value. + */ +fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16) +{ + fw_port_cap32_t caps32 = 0; + + #define CAP16_TO_CAP32(__cap) \ + do { \ + if (caps16 & FW_PORT_CAP_##__cap) \ + caps32 |= FW_PORT_CAP32_##__cap; \ + } while (0) + + CAP16_TO_CAP32(SPEED_100M); + CAP16_TO_CAP32(SPEED_1G); + CAP16_TO_CAP32(SPEED_25G); + CAP16_TO_CAP32(SPEED_10G); + CAP16_TO_CAP32(SPEED_40G); + CAP16_TO_CAP32(SPEED_100G); + CAP16_TO_CAP32(FC_RX); + CAP16_TO_CAP32(FC_TX); + CAP16_TO_CAP32(ANEG); + CAP16_TO_CAP32(MDIX); + CAP16_TO_CAP32(MDIAUTO); + CAP16_TO_CAP32(FEC_RS); + CAP16_TO_CAP32(FEC_BASER_RS); + CAP16_TO_CAP32(802_3_PAUSE); + CAP16_TO_CAP32(802_3_ASM_DIR); + + #undef CAP16_TO_CAP32 + + return caps32; +} + +/** + * lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities + * @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value + * + * Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new + * 32-bit Port Capabilities value. + */ +fw_port_cap32_t lstatus_to_fwcap(u32 lstatus) +{ + fw_port_cap32_t linkattr = 0; + + /* The format of the Link Status in the old + * 16-bit Port Information message isn't the same as the + * 16-bit Port Capabilities bitfield used everywhere else. + */ + if (lstatus & FW_PORT_CMD_RXPAUSE_F) + linkattr |= FW_PORT_CAP32_FC_RX; + if (lstatus & FW_PORT_CMD_TXPAUSE_F) + linkattr |= FW_PORT_CAP32_FC_TX; + if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) + linkattr |= FW_PORT_CAP32_SPEED_100M; + if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) + linkattr |= FW_PORT_CAP32_SPEED_1G; + if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) + linkattr |= FW_PORT_CAP32_SPEED_10G; + if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) + linkattr |= FW_PORT_CAP32_SPEED_25G; + if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) + linkattr |= FW_PORT_CAP32_SPEED_40G; + if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) + linkattr |= FW_PORT_CAP32_SPEED_100G; + + return linkattr; +} + +/** + * csio_init_link_config - initialize a link's SW state + * @lc: pointer to structure holding the link state + * @pcaps: link Port Capabilities + * @acaps: link current Advertised Port Capabilities + * + * Initializes the SW state maintained for each link, including the link's + * capabilities and default speed/flow-control/autonegotiation settings. + */ +static void csio_init_link_config(struct link_config *lc, fw_port_cap32_t pcaps, + fw_port_cap32_t acaps) +{ + lc->pcaps = pcaps; + lc->def_acaps = acaps; + lc->lpacaps = 0; + lc->speed_caps = 0; + lc->speed = 0; + lc->requested_fc = PAUSE_RX | PAUSE_TX; + lc->fc = lc->requested_fc; + + /* + * For Forward Error Control, we default to whatever the Firmware + * tells us the Link is currently advertising. + */ + lc->requested_fec = FEC_AUTO; + lc->fec = fwcap_to_cc_fec(lc->def_acaps); + + /* If the Port is capable of Auto-Negtotiation, initialize it as + * "enabled" and copy over all of the Physical Port Capabilities + * to the Advertised Port Capabilities. Otherwise mark it as + * Auto-Negotiate disabled and select the highest supported speed + * for the link. Note parallel structure in t4_link_l1cfg_core() + * and t4_handle_get_port_info(). + */ + if (lc->pcaps & FW_PORT_CAP32_ANEG) { + lc->acaps = lc->pcaps & ADVERT_MASK; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->acaps = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +static void csio_link_l1cfg(struct link_config *lc, uint16_t fw_caps, + uint32_t *rcaps) +{ + unsigned int fw_mdi = FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO); + fw_port_cap32_t fw_fc, cc_fec, fw_fec, lrcap; + + lc->link_ok = 0; + + /* + * Convert driver coding of Pause Frame Flow Control settings into the + * Firmware's API. + */ + fw_fc = cc_to_fwcap_pause(lc->requested_fc); + + /* + * Convert Common Code Forward Error Control settings into the + * Firmware's API. If the current Requested FEC has "Automatic" + * (IEEE 802.3) specified, then we use whatever the Firmware + * sent us as part of it's IEEE 802.3-based interpratation of + * the Transceiver Module EPROM FEC parameters. Otherwise we + * use whatever is in the current Requested FEC settings. + */ + if (lc->requested_fec & FEC_AUTO) + cc_fec = fwcap_to_cc_fec(lc->def_acaps); + else + cc_fec = lc->requested_fec; + fw_fec = cc_to_fwcap_fec(cc_fec); + + /* Figure out what our Requested Port Capabilities are going to be. + * Note parallel structure in t4_handle_get_port_info() and + * init_link_config(). + */ + if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { + lrcap = (lc->pcaps & ADVERT_MASK) | fw_fc | fw_fec; + lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; + lc->fec = cc_fec; + } else if (lc->autoneg == AUTONEG_DISABLE) { + lrcap = lc->speed_caps | fw_fc | fw_fec | fw_mdi; + lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; + lc->fec = cc_fec; + } else { + lrcap = lc->acaps | fw_fc | fw_fec | fw_mdi; + } + + *rcaps = lrcap; +} + /* * csio_enable_ports - Bring up all available ports. * @hw: HW module. @@ -1418,8 +1647,10 @@ static int csio_enable_ports(struct csio_hw *hw) { struct csio_mb *mbp; + u16 fw_caps = FW_CAPS_UNKNOWN; enum fw_retval retval; uint8_t portid; + fw_port_cap32_t pcaps, acaps, rcaps; int i; mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); @@ -1431,9 +1662,39 @@ csio_enable_ports(struct csio_hw *hw) for (i = 0; i < hw->num_pports; i++) { portid = hw->pport[i].portid; + if (fw_caps == FW_CAPS_UNKNOWN) { + u32 param, val; + + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32)); + val = 1; + + csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO, + hw->pfn, 0, 1, ¶m, &val, false, + NULL); + + if (csio_mb_issue(hw, mbp)) { + csio_err(hw, "failed to issue FW_PARAMS_CMD(r) port:%d\n", + portid); + mempool_free(mbp, hw->mb_mempool); + return -EINVAL; + } + + csio_mb_process_read_params_rsp(hw, mbp, &retval, 1, + &val); + if (retval != FW_SUCCESS) { + csio_err(hw, "FW_PARAMS_CMD(r) port:%d failed: 0x%x\n", + portid, retval); + mempool_free(mbp, hw->mb_mempool); + return -EINVAL; + } + + fw_caps = val; + } + /* Read PORT information */ csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, - false, 0, 0, NULL); + false, 0, fw_caps, NULL); if (csio_mb_issue(hw, mbp)) { csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n", @@ -1442,8 +1703,8 @@ csio_enable_ports(struct csio_hw *hw) return -EINVAL; } - csio_mb_process_read_port_rsp(hw, mbp, &retval, - &hw->pport[i].pcap); + csio_mb_process_read_port_rsp(hw, mbp, &retval, fw_caps, + &pcaps, &acaps); if (retval != FW_SUCCESS) { csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n", portid, retval); @@ -1451,9 +1712,13 @@ csio_enable_ports(struct csio_hw *hw) return -EINVAL; } + csio_init_link_config(&hw->pport[i].link_cfg, pcaps, acaps); + + csio_link_l1cfg(&hw->pport[i].link_cfg, fw_caps, &rcaps); + /* Write back PORT information */ - csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, true, - (PAUSE_RX | PAUSE_TX), hw->pport[i].pcap, NULL); + csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, + true, rcaps, fw_caps, NULL); if (csio_mb_issue(hw, mbp)) { csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n", diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h index 30f5f523c8cc..9e73ef771eb7 100644 --- a/drivers/scsi/csiostor/csio_hw.h +++ b/drivers/scsi/csiostor/csio_hw.h @@ -268,8 +268,62 @@ struct csio_vpd { uint8_t id[ID_LEN + 1]; }; +/* Firmware Port Capabilities types. */ + +typedef u16 fw_port_cap16_t; /* 16-bit Port Capabilities integral value */ +typedef u32 fw_port_cap32_t; /* 32-bit Port Capabilities integral value */ + +enum fw_caps { + FW_CAPS_UNKNOWN = 0, /* 0'ed out initial state */ + FW_CAPS16 = 1, /* old Firmware: 16-bit Port Capabilities */ + FW_CAPS32 = 2, /* new Firmware: 32-bit Port Capabilities */ +}; + +enum cc_pause { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +enum cc_fec { + FEC_AUTO = 1 << 0, /* IEEE 802.3 "automatic" */ + FEC_RS = 1 << 1, /* Reed-Solomon */ + FEC_BASER_RS = 1 << 2 /* BaseR/Reed-Solomon */ +}; + +struct link_config { + fw_port_cap32_t pcaps; /* link capabilities */ + fw_port_cap32_t def_acaps; /* default advertised capabilities */ + fw_port_cap32_t acaps; /* advertised capabilities */ + fw_port_cap32_t lpacaps; /* peer advertised capabilities */ + + fw_port_cap32_t speed_caps; /* speed(s) user has requested */ + unsigned int speed; /* actual link speed (Mb/s) */ + + enum cc_pause requested_fc; /* flow control user has requested */ + enum cc_pause fc; /* actual link flow control */ + + enum cc_fec requested_fec; /* Forward Error Correction: */ + enum cc_fec fec; /* requested and actual in use */ + + unsigned char autoneg; /* autonegotiating? */ + + unsigned char link_ok; /* link up? */ + unsigned char link_down_rc; /* link down reason */ +}; + +#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16) + +#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \ + FW_PORT_CAP32_ANEG) + +/* Enable or disable autonegotiation. */ +#define AUTONEG_DISABLE 0x00 +#define AUTONEG_ENABLE 0x01 + struct csio_pport { uint16_t pcap; + uint16_t acap; uint8_t portid; uint8_t link_status; uint16_t link_speed; @@ -278,6 +332,7 @@ struct csio_pport { uint8_t rsvd1; uint8_t rsvd2; uint8_t rsvd3; + struct link_config link_cfg; }; /* fcoe resource information */ @@ -582,6 +637,10 @@ int csio_hw_slow_intr_handler(struct csio_hw *); int csio_handle_intr_status(struct csio_hw *, unsigned int, const struct intr_info *); +fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps); +fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16); +fw_port_cap32_t lstatus_to_fwcap(u32 lstatus); + int csio_hw_start(struct csio_hw *); int csio_hw_stop(struct csio_hw *); int csio_hw_reset(struct csio_hw *); diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index 7dbbbb81a1e7..cc5611efc7a9 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -352,6 +352,14 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) val = htonl(FC_PORTSPEED_1GBIT); else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G) val = htonl(FC_PORTSPEED_10GBIT); + else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_25G) + val = htonl(FC_PORTSPEED_25GBIT); + else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_40G) + val = htonl(FC_PORTSPEED_40GBIT); + else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_50G) + val = htonl(FC_PORTSPEED_50GBIT); + else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_100G) + val = htonl(FC_PORTSPEED_100GBIT); else val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN); csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED, diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c index 5f4e0a787bd1..c026417269c3 100644 --- a/drivers/scsi/csiostor/csio_mb.c +++ b/drivers/scsi/csiostor/csio_mb.c @@ -326,10 +326,6 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET); } -#define CSIO_ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ - FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G |\ - FW_PORT_CAP_ANEG) - /* * csio_mb_port- FW PORT command helper * @hw: The HW structure @@ -344,11 +340,10 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, */ void csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, - uint8_t portid, bool wr, uint32_t fc, uint16_t caps, + u8 portid, bool wr, uint32_t fc, uint16_t fw_caps, void (*cbfn) (struct csio_hw *, struct csio_mb *)) { struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb); - unsigned int lfc = 0, mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO); CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1); @@ -358,26 +353,24 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, FW_PORT_CMD_PORTID_V(portid)); if (!wr) { cmdp->action_to_len16 = htonl( - FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) | + FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 + ? FW_PORT_ACTION_GET_PORT_INFO + : FW_PORT_ACTION_GET_PORT_INFO32) | FW_CMD_LEN16_V(sizeof(*cmdp) / 16)); return; } /* Set port */ cmdp->action_to_len16 = htonl( - FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) | + FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 + ? FW_PORT_ACTION_L1_CFG + : FW_PORT_ACTION_L1_CFG32) | FW_CMD_LEN16_V(sizeof(*cmdp) / 16)); - if (fc & PAUSE_RX) - lfc |= FW_PORT_CAP_FC_RX; - if (fc & PAUSE_TX) - lfc |= FW_PORT_CAP_FC_TX; - - if (!(caps & FW_PORT_CAP_ANEG)) - cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) | lfc); + if (fw_caps == FW_CAPS16) + cmdp->u.l1cfg.rcap = cpu_to_be32(fc); else - cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) | - lfc | mdi); + cmdp->u.l1cfg32.rcap32 = cpu_to_be32(fc); } /* @@ -390,14 +383,22 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, */ void csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp, - enum fw_retval *retval, uint16_t *caps) + enum fw_retval *retval, uint16_t fw_caps, + u32 *pcaps, u32 *acaps) { struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb); *retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16)); - if (*retval == FW_SUCCESS) - *caps = ntohs(rsp->u.info.pcap); + if (*retval == FW_SUCCESS) { + if (fw_caps == FW_CAPS16) { + *pcaps = fwcaps16_to_caps32(ntohs(rsp->u.info.pcap)); + *acaps = fwcaps16_to_caps32(ntohs(rsp->u.info.acap)); + } else { + *pcaps = ntohs(rsp->u.info32.pcaps32); + *acaps = ntohs(rsp->u.info32.acaps32); + } + } } /* @@ -1409,6 +1410,7 @@ csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd) uint32_t link_status; uint16_t action; uint8_t mod_type; + fw_port_cap32_t linkattr; if (opcode == FW_PORT_CMD) { pcmd = (struct fw_port_cmd *)cmd; @@ -1416,22 +1418,34 @@ csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd) ntohl(pcmd->op_to_portid)); action = FW_PORT_CMD_ACTION_G( ntohl(pcmd->action_to_len16)); - if (action != FW_PORT_ACTION_GET_PORT_INFO) { + if (action != FW_PORT_ACTION_GET_PORT_INFO && + action != FW_PORT_ACTION_GET_PORT_INFO32) { csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n", action); return -EINVAL; } - link_status = ntohl(pcmd->u.info.lstatus_to_modtype); - mod_type = FW_PORT_CMD_MODTYPE_G(link_status); + if (action == FW_PORT_ACTION_GET_PORT_INFO) { + link_status = ntohl(pcmd->u.info.lstatus_to_modtype); + mod_type = FW_PORT_CMD_MODTYPE_G(link_status); + linkattr = lstatus_to_fwcap(link_status); + + hw->pport[port_id].link_status = + FW_PORT_CMD_LSTATUS_G(link_status); + } else { + link_status = + ntohl(pcmd->u.info32.lstatus32_to_cbllen32); + mod_type = FW_PORT_CMD_MODTYPE32_G(link_status); + linkattr = ntohl(pcmd->u.info32.linkattr32); + + hw->pport[port_id].link_status = + FW_PORT_CMD_LSTATUS32_G(link_status); + } - hw->pport[port_id].link_status = - FW_PORT_CMD_LSTATUS_G(link_status); - hw->pport[port_id].link_speed = - FW_PORT_CMD_LSPEED_G(link_status); + hw->pport[port_id].link_speed = fwcap_to_fwspeed(linkattr); csio_info(hw, "Port:%x - LINK %s\n", port_id, - FW_PORT_CMD_LSTATUS_G(link_status) ? "UP" : "DOWN"); + hw->pport[port_id].link_status ? "UP" : "DOWN"); if (mod_type != hw->pport[port_id].mod_type) { hw->pport[port_id].mod_type = mod_type; diff --git a/drivers/scsi/csiostor/csio_mb.h b/drivers/scsi/csiostor/csio_mb.h index a6823df73015..b07e891c5936 100644 --- a/drivers/scsi/csiostor/csio_mb.h +++ b/drivers/scsi/csiostor/csio_mb.h @@ -88,12 +88,6 @@ enum csio_dev_state { FW_PARAMS_PARAM_Y_V(0) | \ FW_PARAMS_PARAM_Z_V(0)) -enum { - PAUSE_RX = 1 << 0, - PAUSE_TX = 1 << 1, - PAUSE_AUTONEG = 1 << 2 -}; - #define CSIO_INIT_MBP(__mbp, __cp, __tmo, __priv, __fn, __clear) \ do { \ if (__clear) \ @@ -189,7 +183,8 @@ void csio_mb_port(struct csio_hw *, struct csio_mb *, uint32_t, void (*) (struct csio_hw *, struct csio_mb *)); void csio_mb_process_read_port_rsp(struct csio_hw *, struct csio_mb *, - enum fw_retval *, uint16_t *); + enum fw_retval *, uint16_t, + uint32_t *, uint32_t *); void csio_mb_initialize(struct csio_hw *, struct csio_mb *, uint32_t, void (*)(struct csio_hw *, struct csio_mb *)); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 4b44325d1a82..12dc7100bb4c 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -138,12 +138,12 @@ static void release_port_group(struct kref *kref) static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff, int bufflen, struct scsi_sense_hdr *sshdr, int flags) { - u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)]; + u8 cdb[MAX_COMMAND_SIZE]; int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; /* Prepare the command. */ - memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN)); + memset(cdb, 0x0, MAX_COMMAND_SIZE); cdb[0] = MAINTENANCE_IN; if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP)) cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; @@ -166,7 +166,7 @@ static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff, static int submit_stpg(struct scsi_device *sdev, int group_id, struct scsi_sense_hdr *sshdr) { - u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)]; + u8 cdb[MAX_COMMAND_SIZE]; unsigned char stpg_data[8]; int stpg_len = 8; int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | @@ -178,7 +178,7 @@ static int submit_stpg(struct scsi_device *sdev, int group_id, put_unaligned_be16(group_id, &stpg_data[6]); /* Prepare the command. */ - memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT)); + memset(cdb, 0x0, MAX_COMMAND_SIZE); cdb[0] = MAINTENANCE_OUT; cdb[1] = MO_SET_TARGET_PGS; put_unaligned_be32(stpg_len, &cdb[6]); @@ -214,8 +214,8 @@ static struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size, /* * alua_alloc_pg - Allocate a new port_group structure * @sdev: scsi device - * @h: alua device_handler data * @group_id: port group id + * @tpgs: target port group settings * * Allocate a new port_group structure for a given * device. diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 6a2792f3a37e..95c47909a58f 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -249,7 +249,7 @@ static int send_trespass_cmd(struct scsi_device *sdev, struct clariion_dh_data *csdev) { unsigned char *page22; - unsigned char cdb[COMMAND_SIZE(MODE_SELECT)]; + unsigned char cdb[MAX_COMMAND_SIZE]; int err, res = SCSI_DH_OK, len; struct scsi_sense_hdr sshdr; u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 7af31a1247ee..d27fabae8ddd 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -533,7 +533,7 @@ static void send_mode_select(struct work_struct *work) int err = SCSI_DH_OK, retry_cnt = RDAC_RETRY_COUNT; struct rdac_queue_data *tmp, *qdata; LIST_HEAD(list); - unsigned char cdb[COMMAND_SIZE(MODE_SELECT_10)]; + unsigned char cdb[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sshdr; unsigned int data_size; u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index a00d822e3142..6866975b25f3 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -302,16 +302,14 @@ rebuild_sys_tab: } -/* - * scsi_unregister will be called AFTER we return. - */ -static int adpt_release(struct Scsi_Host *host) +static void adpt_release(adpt_hba *pHba) { - adpt_hba* pHba = (adpt_hba*) host->hostdata[0]; + struct Scsi_Host *shost = pHba->host; + + scsi_remove_host(shost); // adpt_i2o_quiesce_hba(pHba); adpt_i2o_delete_hba(pHba); - scsi_unregister(host); - return 0; + scsi_host_put(shost); } @@ -801,14 +799,17 @@ static int __adpt_reset(struct scsi_cmnd* cmd) { adpt_hba* pHba; int rcode; + char name[32]; + pHba = (adpt_hba*)cmd->device->host->hostdata[0]; - printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n",pHba->name,cmd->device->channel,pHba->channel[cmd->device->channel].tid ); + strncpy(name, pHba->name, sizeof(name)); + printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n", name, cmd->device->channel, pHba->channel[cmd->device->channel].tid); rcode = adpt_hba_reset(pHba); if(rcode == 0){ - printk(KERN_WARNING"%s: HBA reset complete\n",pHba->name); + printk(KERN_WARNING"%s: HBA reset complete\n", name); return SUCCESS; } else { - printk(KERN_WARNING"%s: HBA reset failed (%x)\n",pHba->name, rcode); + printk(KERN_WARNING"%s: HBA reset failed (%x)\n", name, rcode); return FAILED; } } @@ -1087,8 +1088,6 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba) mutex_lock(&adpt_configuration_lock); - // scsi_unregister calls our adpt_release which - // does a quiese if(pHba->host){ free_irq(pHba->host->irq, pHba); } @@ -3595,11 +3594,9 @@ static void __exit adpt_exit(void) { adpt_hba *pHba, *next; - for (pHba = hba_chain; pHba; pHba = pHba->next) - scsi_remove_host(pHba->host); for (pHba = hba_chain; pHba; pHba = next) { next = pHba->next; - adpt_release(pHba->host); + adpt_release(pHba); } } diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 1fa345ab8ecb..dfc8d2eaa09e 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -32,7 +32,6 @@ static int adpt_detect(struct scsi_host_template * sht); static int adpt_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd); static int adpt_abort(struct scsi_cmnd * cmd); static int adpt_reset(struct scsi_cmnd* cmd); -static int adpt_release(struct Scsi_Host *host); static int adpt_slave_configure(struct scsi_device *); static const char *adpt_info(struct Scsi_Host *pSHost); diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c deleted file mode 100644 index 6501c330d8c8..000000000000 --- a/drivers/scsi/eata.c +++ /dev/null @@ -1,2571 +0,0 @@ -/* - * eata.c - Low-level driver for EATA/DMA SCSI host adapters. - * - * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 - * + Update for new IRQ API. - * + Use "goto" when appropriate. - * + Drop eata.h. - * + Update for new module_param API. - * + Module parameters can now be specified only in the - * same format as the kernel boot options. - * - * boot option old module param - * ----------- ------------------ - * addr,... io_port=addr,... - * lc:[y|n] linked_comm=[1|0] - * mq:xx max_queue_depth=xx - * tm:[0|1|2] tag_mode=[0|1|2] - * et:[y|n] ext_tran=[1|0] - * rs:[y|n] rev_scan=[1|0] - * ip:[y|n] isa_probe=[1|0] - * ep:[y|n] eisa_probe=[1|0] - * pp:[y|n] pci_probe=[1|0] - * - * A valid example using the new parameter format is: - * modprobe eata "eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n" - * - * which is equivalent to the old format: - * modprobe eata io_port=0x7410,0x230 linked_comm=1 tag_mode=0 \ - * max_queue_depth=4 eisa_probe=0 - * - * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 - * + Release irq before calling scsi_register. - * - * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 - * + Release driver_lock before calling scsi_register. - * - * 11 Nov 2002 Rev. 8.01 for linux 2.5.47 - * + Fixed bios_param and scsicam_bios_param calling parameters. - * - * 28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4 - * + Use new tcq and adjust_queue_depth api. - * + New command line option (tm:[0-2]) to choose the type of tags: - * 0 -> disable tagging ; 1 -> simple tags ; 2 -> ordered tags. - * Default is tm:0 (tagged commands disabled). - * For compatibility the "tc:" option is an alias of the "tm:" - * option; tc:n is equivalent to tm:0 and tc:y is equivalent to - * tm:1. - * + The tagged_comm module parameter has been removed, use tag_mode - * instead, equivalent to the "tm:" boot option. - * - * 10 Oct 2002 Rev. 7.70 for linux 2.5.42 - * + Foreport from revision 6.70. - * - * 25 Jun 2002 Rev. 6.70 for linux 2.4.19 - * + This release is the first one tested on a Big Endian platform: - * fixed endian-ness problem due to bitfields; - * fixed endian-ness problem in read_pio. - * + Added new options for selectively probing ISA, EISA and PCI bus: - * - * Boot option Parameter name Default according to - * - * ip:[y|n] isa_probe=[1|0] CONFIG_ISA defined - * ep:[y|n] eisa_probe=[1|0] CONFIG_EISA defined - * pp:[y|n] pci_probe=[1|0] CONFIG_PCI defined - * - * The default action is to perform probing if the corresponding - * bus is configured and to skip probing otherwise. - * - * + If pci_probe is in effect and a list of I/O ports is specified - * as parameter or boot option, pci_enable_device() is performed - * on all pci devices matching PCI_CLASS_STORAGE_SCSI. - * - * 21 Feb 2002 Rev. 6.52 for linux 2.4.18 - * + Backport from rev. 7.22 (use io_request_lock). - * - * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 - * + Remove any reference to virt_to_bus(). - * + Fix pio hang while detecting multiple HBAs. - * + Fixed a board detection bug: in a system with - * multiple ISA/EISA boards, all but the first one - * were erroneously detected as PCI. - * - * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 - * + Use the dynamic DMA mapping API. - * - * 19 Dec 2001 Rev. 7.02 for linux 2.5.1 - * + Use SCpnt->sc_data_direction if set. - * + Use sglist.page instead of sglist.address. - * - * 11 Dec 2001 Rev. 7.00 for linux 2.5.1 - * + Use host->host_lock instead of io_request_lock. - * - * 1 May 2001 Rev. 6.05 for linux 2.4.4 - * + Clean up all pci related routines. - * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) - * - * 30 Jan 2001 Rev. 6.04 for linux 2.4.1 - * + Call pci_resource_start after pci_enable_device. - * - * 25 Jan 2001 Rev. 6.03 for linux 2.4.0 - * + "check_region" call replaced by "request_region". - * - * 22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11 - * + Return code checked when calling pci_enable_device. - * + Removed old scsi error handling support. - * + The obsolete boot option flag eh:n is silently ignored. - * + Removed error messages while a disk drive is powered up at - * boot time. - * + Improved boot messages: all tagged capable device are - * indicated as "tagged" or "soft-tagged" : - * - "soft-tagged" means that the driver is trying to do its - * own tagging (i.e. the tc:y option is in effect); - * - "tagged" means that the device supports tagged commands, - * but the driver lets the HBA be responsible for tagging - * support. - * - * 16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18 - * + Updated to the new __setup interface for boot command line options. - * + When loaded as a module, accepts the new parameter boot_options - * which value is a string with the same format of the kernel boot - * command line options. A valid example is: - * modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"' - * - * 9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17 - * + 64bit cleanup for Linux/Alpha platform support - * (contribution from H.J. Lu). - * - * 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11 - * + Removed pre-2.2 source code compatibility. - * + Added call to pci_set_master. - * - * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111 - * + Added command line option (rs:[y|n]) to reverse the scan order - * of PCI boards. The default is rs:y, which reverses the BIOS order - * while registering PCI boards. The default value rs:y generates - * the same order of all previous revisions of this driver. - * Pls. note that "BIOS order" might have been reversed itself - * after the 2.1.9x PCI modifications in the linux kernel. - * The rs value is ignored when the explicit list of addresses - * is used by the "eata=port0,port1,..." command line option. - * + Added command line option (et:[y|n]) to force use of extended - * translation (255 heads, 63 sectors) as disk geometry. - * The default is et:n, which uses the disk geometry returned - * by scsicam_bios_param. The default value et:n is compatible with - * all previous revisions of this driver. - * - * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104 - * Increased busy timeout from 10 msec. to 200 msec. while - * processing interrupts. - * - * 16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102 - * Improved abort handling during the eh recovery process. - * - * 13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101 - * The driver is now fully SMP safe, including the - * abort and reset routines. - * Added command line options (eh:[y|n]) to choose between - * new_eh_code and the old scsi code. - * If linux version >= 2.1.101 the default is eh:y, while the eh - * option is ignored for previous releases and the old scsi code - * is used. - * - * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97 - * Reworked interrupt handler. - * - * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95 - * Major reliability improvement: when a batch with overlapping - * requests is detected, requests are queued one at a time - * eliminating any possible board or drive reordering. - * - * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95 - * Improved SMP support (if linux version >= 2.1.95). - * - * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94 - * Added support for new PCI code and IO-APIC remapping of irqs. - * Performance improvement: when sequential i/o is detected, - * always use direct sort instead of reverse sort. - * - * 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92 - * io_port is now unsigned long. - * - * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88 - * Use new scsi error handling code (if linux version >= 2.1.88). - * Use new interrupt code. - * - * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55 - * Use of udelay inside the wait loops to avoid timeout - * problems with fast cpus. - * Removed check about useless calls to the interrupt service - * routine (reported on SMP systems only). - * At initialization time "sorted/unsorted" is displayed instead - * of "linked/unlinked" to reinforce the fact that "linking" is - * nothing but "elevator sorting" in the actual implementation. - * - * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38 - * Use of serial_number_at_timeout in abort and reset processing. - * Use of the __initfunc and __initdata macro in setup code. - * Minor cleanups in the list_statistics code. - * Increased controller busy timeout in order to better support - * slow SCSI devices. - * - * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26 - * When loading as a module, parameter passing is now supported - * both in 2.0 and in 2.1 style. - * Fixed data transfer direction for some SCSI opcodes. - * Immediate acknowledge to request sense commands. - * Linked commands to each disk device are now reordered by elevator - * sorting. Rare cases in which reordering of write requests could - * cause wrong results are managed. - * Fixed spurious timeouts caused by long simple queue tag sequences. - * New command line option (tm:[0-3]) to choose the type of tags: - * 0 -> mixed (default); 1 -> simple; 2 -> head; 3 -> ordered. - * - * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28 - * Added command line options to enable/disable linked commands - * (lc:[y|n]), tagged commands (tc:[y|n]) and to set the max queue - * depth (mq:xx). Default is "eata=lc:n,tc:n,mq:16". - * Improved command linking. - * Documented how to setup RAID-0 with DPT SmartRAID boards. - * - * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27 - * Added linked command support. - * Improved detection of PCI boards using ISA base addresses. - * - * 3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27 - * Added support for tagged commands and queue depth adjustment. - * - * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26 - * When CONFIG_PCI is defined, BIOS32 is used to include in the - * list of i/o ports to be probed all the PCI SCSI controllers. - * The list of i/o ports to be probed can be overwritten by the - * "eata=port0,port1,...." boot command line option. - * Scatter/gather lists are now allocated by a number of kmalloc - * calls, in order to avoid the previous size limit of 64Kb. - * - * 16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25 - * Added support for EATA 2.0C, PCI, multichannel and wide SCSI. - * - * 27 Sep 1996 rev. 2.12 for linux 2.1.0 - * Portability cleanups (virtual/bus addressing, little/big endian - * support). - * - * 09 Jul 1996 rev. 2.11 for linux 2.0.4 - * Number of internal retries is now limited. - * - * 16 Apr 1996 rev. 2.10 for linux 1.3.90 - * New argument "reset_flags" to the reset routine. - * - * 6 Jul 1995 rev. 2.01 for linux 1.3.7 - * Update required by the new /proc/scsi support. - * - * 11 Mar 1995 rev. 2.00 for linux 1.2.0 - * Fixed a bug which prevented media change detection for removable - * disk drives. - * - * 23 Feb 1995 rev. 1.18 for linux 1.1.94 - * Added a check for scsi_register returning NULL. - * - * 11 Feb 1995 rev. 1.17 for linux 1.1.91 - * Now DEBUG_RESET is disabled by default. - * Register a board even if it does not assert DMA protocol support - * (DPT SK2011B does not report correctly the dmasup bit). - * - * 9 Feb 1995 rev. 1.16 for linux 1.1.90 - * Use host->wish_block instead of host->block. - * New list of Data Out SCSI commands. - * - * 8 Feb 1995 rev. 1.15 for linux 1.1.89 - * Cleared target_time_out counter while performing a reset. - * All external symbols renamed to avoid possible name conflicts. - * - * 28 Jan 1995 rev. 1.14 for linux 1.1.86 - * Added module support. - * Log and do a retry when a disk drive returns a target status - * different from zero on a recovered error. - * - * 24 Jan 1995 rev. 1.13 for linux 1.1.85 - * Use optimized board configuration, with a measured performance - * increase in the range 10%-20% on i/o throughput. - * - * 16 Jan 1995 rev. 1.12 for linux 1.1.81 - * Fix mscp structure comments (no functional change). - * Display a message if check_region detects a port address - * already in use. - * - * 17 Dec 1994 rev. 1.11 for linux 1.1.74 - * Use the scsicam_bios_param routine. This allows an easy - * migration path from disk partition tables created using - * different SCSI drivers and non optimal disk geometry. - * - * 15 Dec 1994 rev. 1.10 for linux 1.1.74 - * Added support for ISA EATA boards (DPT PM2011, DPT PM2021). - * The host->block flag is set for all the detected ISA boards. - * The detect routine no longer enforces LEVEL triggering - * for EISA boards, it just prints a warning message. - * - * 30 Nov 1994 rev. 1.09 for linux 1.1.68 - * Redo i/o on target status CHECK_CONDITION for TYPE_DISK only. - * Added optional support for using a single board at a time. - * - * 18 Nov 1994 rev. 1.08 for linux 1.1.64 - * Forces sg_tablesize = 64 and can_queue = 64 if these - * values are not correctly detected (DPT PM2012). - * - * 14 Nov 1994 rev. 1.07 for linux 1.1.63 Final BETA release. - * 04 Aug 1994 rev. 1.00 for linux 1.1.39 First BETA release. - * - * - * This driver is based on the CAM (Common Access Method Committee) - * EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol. - * - * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) - * - * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. - * - */ - -/* - * - * Here is a brief description of the DPT SCSI host adapters. - * All these boards provide an EATA/DMA compatible programming interface - * and are fully supported by this driver in any configuration, including - * multiple SCSI channels: - * - * PM2011B/9X - Entry Level ISA - * PM2021A/9X - High Performance ISA - * PM2012A Old EISA - * PM2012B Old EISA - * PM2022A/9X - Entry Level EISA - * PM2122A/9X - High Performance EISA - * PM2322A/9X - Extra High Performance EISA - * PM3021 - SmartRAID Adapter for ISA - * PM3222 - SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI) - * PM3224 - SmartRAID Adapter for PCI (PM3224W is 16-bit wide SCSI) - * PM33340UW - SmartRAID Adapter for PCI ultra wide multichannel - * - * The above list is just an indication: as a matter of fact all DPT - * boards using the EATA/DMA protocol are supported by this driver, - * since they use exactely the same programming interface. - * - * The DPT PM2001 provides only the EATA/PIO interface and hence is not - * supported by this driver. - * - * This code has been tested with up to 3 Distributed Processing Technology - * PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers, - * in any combination of private and shared IRQ. - * PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS - * v003.D0, firmware v07G.0). - * - * DPT SmartRAID boards support "Hardware Array" - a group of disk drives - * which are all members of the same RAID-0, RAID-1 or RAID-5 array implemented - * in host adapter hardware. Hardware Arrays are fully compatible with this - * driver, since they look to it as a single disk drive. - * - * WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix" - * as the current OS in the DPTMGR "Initial System Installation" menu. - * Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0), - * which is not supported by the actual SCSI subsystem. - * To get the "Array Group" functionality, the Linux MD driver must be used - * instead of the DPT "Array Group" feature. - * - * Multiple ISA, EISA and PCI boards can be configured in the same system. - * It is suggested to put all the EISA boards on the same IRQ level, all - * the PCI boards on another IRQ level, while ISA boards cannot share - * interrupts. - * - * If you configure multiple boards on the same IRQ, the interrupt must - * be _level_ triggered (not _edge_ triggered). - * - * This driver detects EATA boards by probes at fixed port addresses, - * so no BIOS32 or PCI BIOS support is required. - * The suggested way to detect a generic EATA PCI board is to force on it - * any unused EISA address, even if there are other controllers on the EISA - * bus, or even if you system has no EISA bus at all. - * Do not force any ISA address on EATA PCI boards. - * - * If PCI bios support is configured into the kernel, BIOS32 is used to - * include in the list of i/o ports to be probed all the PCI SCSI controllers. - * - * Due to a DPT BIOS "feature", it might not be possible to force an EISA - * address on more than a single DPT PCI board, so in this case you have to - * let the PCI BIOS assign the addresses. - * - * The sequence of detection probes is: - * - * - ISA 0x1F0; - * - PCI SCSI controllers (only if BIOS32 is available); - * - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15); - * - ISA 0x170, 0x230, 0x330. - * - * The above list of detection probes can be totally replaced by the - * boot command line option: "eata=port0,port1,port2,...", where the - * port0, port1... arguments are ISA/EISA/PCI addresses to be probed. - * For example using "eata=0x7410,0x7450,0x230", the driver probes - * only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230, - * in this order; "eata=0" totally disables this driver. - * - * After the optional list of detection probes, other possible command line - * options are: - * - * et:y force use of extended translation (255 heads, 63 sectors); - * et:n use disk geometry detected by scsicam_bios_param; - * rs:y reverse scan order while detecting PCI boards; - * rs:n use BIOS order while detecting PCI boards; - * lc:y enables linked commands; - * lc:n disables linked commands; - * tm:0 disables tagged commands (same as tc:n); - * tm:1 use simple queue tags (same as tc:y); - * tm:2 use ordered queue tags (same as tc:2); - * mq:xx set the max queue depth to the value xx (2 <= xx <= 32). - * - * The default value is: "eata=lc:n,mq:16,tm:0,et:n,rs:n". - * An example using the list of detection probes could be: - * "eata=0x7410,0x230,lc:y,tm:2,mq:4,et:n". - * - * When loading as a module, parameters can be specified as well. - * The above example would be (use 1 in place of y and 0 in place of n): - * - * modprobe eata io_port=0x7410,0x230 linked_comm=1 \ - * max_queue_depth=4 ext_tran=0 tag_mode=2 \ - * rev_scan=1 - * - * ---------------------------------------------------------------------------- - * In this implementation, linked commands are designed to work with any DISK - * or CD-ROM, since this linking has only the intent of clustering (time-wise) - * and reordering by elevator sorting commands directed to each device, - * without any relation with the actual SCSI protocol between the controller - * and the device. - * If Q is the queue depth reported at boot time for each device (also named - * cmds/lun) and Q > 2, whenever there is already an active command to the - * device all other commands to the same device (up to Q-1) are kept waiting - * in the elevator sorting queue. When the active command completes, the - * commands in this queue are sorted by sector address. The sort is chosen - * between increasing or decreasing by minimizing the seek distance between - * the sector of the commands just completed and the sector of the first - * command in the list to be sorted. - * Trivial math assures that the unsorted average seek distance when doing - * random seeks over S sectors is S/3. - * When (Q-1) requests are uniformly distributed over S sectors, the average - * distance between two adjacent requests is S/((Q-1) + 1), so the sorted - * average seek distance for (Q-1) random requests over S sectors is S/Q. - * The elevator sorting hence divides the seek distance by a factor Q/3. - * The above pure geometric remarks are valid in all cases and the - * driver effectively reduces the seek distance by the predicted factor - * when there are Q concurrent read i/o operations on the device, but this - * does not necessarily results in a noticeable performance improvement: - * your mileage may vary.... - * - * Note: command reordering inside a batch of queued commands could cause - * wrong results only if there is at least one write request and the - * intersection (sector-wise) of all requests is not empty. - * When the driver detects a batch including overlapping requests - * (a really rare event) strict serial (pid) order is enforced. - * ---------------------------------------------------------------------------- - * The extended translation option (et:y) is useful when using large physical - * disks/arrays. It could also be useful when switching between Adaptec boards - * and DPT boards without reformatting the disk. - * When a boot disk is partitioned with extended translation, in order to - * be able to boot it with a DPT board is could be necessary to add to - * lilo.conf additional commands as in the following example: - * - * fix-table - * disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546 - * - * where the above geometry should be replaced with the one reported at - * power up by the DPT controller. - * ---------------------------------------------------------------------------- - * - * The boards are named EATA0, EATA1,... according to the detection order. - * - * In order to support multiple ISA boards in a reliable way, - * the driver sets host->wish_block = 1 for all ISA boards. - */ - -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/blkdev.h> -#include <linux/interrupt.h> -#include <linux/stat.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ctype.h> -#include <linux/spinlock.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <asm/byteorder.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/irq.h> - -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_tcq.h> -#include <scsi/scsicam.h> - -static int eata2x_detect(struct scsi_host_template *); -static int eata2x_release(struct Scsi_Host *); -static int eata2x_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int eata2x_eh_abort(struct scsi_cmnd *); -static int eata2x_eh_host_reset(struct scsi_cmnd *); -static int eata2x_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int eata2x_slave_configure(struct scsi_device *); - -static struct scsi_host_template driver_template = { - .name = "EATA/DMA 2.0x rev. 8.10.00 ", - .detect = eata2x_detect, - .release = eata2x_release, - .queuecommand = eata2x_queuecommand, - .eh_abort_handler = eata2x_eh_abort, - .eh_host_reset_handler = eata2x_eh_host_reset, - .bios_param = eata2x_bios_param, - .slave_configure = eata2x_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) -#error "Adjust your <asm/byteorder.h> defines" -#endif - -/* Subversion values */ -#define ISA 0 -#define ESA 1 - -#undef FORCE_CONFIG - -#undef DEBUG_LINKED_COMMANDS -#undef DEBUG_DETECT -#undef DEBUG_PCI_DETECT -#undef DEBUG_INTERRUPT -#undef DEBUG_RESET -#undef DEBUG_GENERATE_ERRORS -#undef DEBUG_GENERATE_ABORTS -#undef DEBUG_GEOMETRY - -#define MAX_ISA 4 -#define MAX_VESA 0 -#define MAX_EISA 15 -#define MAX_PCI 16 -#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI) -#define MAX_CHANNEL 4 -#define MAX_LUN 32 -#define MAX_TARGET 32 -#define MAX_MAILBOXES 64 -#define MAX_SGLIST 64 -#define MAX_LARGE_SGLIST 122 -#define MAX_INTERNAL_RETRIES 64 -#define MAX_CMD_PER_LUN 2 -#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN) - -#define SKIP ULONG_MAX -#define FREE 0 -#define IN_USE 1 -#define LOCKED 2 -#define IN_RESET 3 -#define IGNORE 4 -#define READY 5 -#define ABORTING 6 -#define NO_DMA 0xff -#define MAXLOOP 10000 -#define TAG_DISABLED 0 -#define TAG_SIMPLE 1 -#define TAG_ORDERED 2 - -#define REG_CMD 7 -#define REG_STATUS 7 -#define REG_AUX_STATUS 8 -#define REG_DATA 0 -#define REG_DATA2 1 -#define REG_SEE 6 -#define REG_LOW 2 -#define REG_LM 3 -#define REG_MID 4 -#define REG_MSB 5 -#define REGION_SIZE 9UL -#define MAX_ISA_ADDR 0x03ff -#define MIN_EISA_ADDR 0x1c88 -#define MAX_EISA_ADDR 0xfc88 -#define BSY_ASSERTED 0x80 -#define DRQ_ASSERTED 0x08 -#define ABSY_ASSERTED 0x01 -#define IRQ_ASSERTED 0x02 -#define READ_CONFIG_PIO 0xf0 -#define SET_CONFIG_PIO 0xf1 -#define SEND_CP_PIO 0xf2 -#define RECEIVE_SP_PIO 0xf3 -#define TRUNCATE_XFR_PIO 0xf4 -#define RESET_PIO 0xf9 -#define READ_CONFIG_DMA 0xfd -#define SET_CONFIG_DMA 0xfe -#define SEND_CP_DMA 0xff -#define ASOK 0x00 -#define ASST 0x01 - -#define YESNO(a) ((a) ? 'y' : 'n') -#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM) - -/* "EATA", in Big Endian format */ -#define EATA_SIG_BE 0x45415441 - -/* Number of valid bytes in the board config structure for EATA 2.0x */ -#define EATA_2_0A_SIZE 28 -#define EATA_2_0B_SIZE 30 -#define EATA_2_0C_SIZE 34 - -/* Board info structure */ -struct eata_info { - u_int32_t data_len; /* Number of valid bytes after this field */ - u_int32_t sign; /* ASCII "EATA" signature */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar version : 4, - : 4; - unchar haaval : 1, - ata : 1, - drqvld : 1, - dmasup : 1, - morsup : 1, - trnxfr : 1, - tarsup : 1, - ocsena : 1; -#else - unchar : 4, /* unused low nibble */ - version : 4; /* EATA version, should be 0x1 */ - unchar ocsena : 1, /* Overlap Command Support Enabled */ - tarsup : 1, /* Target Mode Supported */ - trnxfr : 1, /* Truncate Transfer Cmd NOT Necessary */ - morsup : 1, /* More Supported */ - dmasup : 1, /* DMA Supported */ - drqvld : 1, /* DRQ Index (DRQX) is valid */ - ata : 1, /* This is an ATA device */ - haaval : 1; /* Host Adapter Address Valid */ -#endif - - ushort cp_pad_len; /* Number of pad bytes after cp_len */ - unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */ - u_int32_t cp_len; /* Number of valid bytes in cp */ - u_int32_t sp_len; /* Number of valid bytes in sp */ - ushort queue_size; /* Max number of cp that can be queued */ - ushort unused; - ushort scatt_size; /* Max number of entries in scatter/gather table */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar drqx : 2, - second : 1, - irq_tr : 1, - irq : 4; - unchar sync; - unchar : 4, - res1 : 1, - large_sg : 1, - forcaddr : 1, - isaena : 1; - unchar max_chan : 3, - max_id : 5; - unchar max_lun; - unchar eisa : 1, - pci : 1, - idquest : 1, - m1 : 1, - : 4; -#else - unchar irq : 4, /* Interrupt Request assigned to this controller */ - irq_tr : 1, /* 0 for edge triggered, 1 for level triggered */ - second : 1, /* 1 if this is a secondary (not primary) controller */ - drqx : 2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */ - unchar sync; /* 1 if scsi target id 7...0 is running sync scsi */ - - /* Structure extension defined in EATA 2.0B */ - unchar isaena : 1, /* ISA i/o addressing is disabled/enabled */ - forcaddr : 1, /* Port address has been forced */ - large_sg : 1, /* 1 if large SG lists are supported */ - res1 : 1, - : 4; - unchar max_id : 5, /* Max SCSI target ID number */ - max_chan : 3; /* Max SCSI channel number on this board */ - - /* Structure extension defined in EATA 2.0C */ - unchar max_lun; /* Max SCSI LUN number */ - unchar - : 4, - m1 : 1, /* This is a PCI with an M1 chip installed */ - idquest : 1, /* RAIDNUM returned is questionable */ - pci : 1, /* This board is PCI */ - eisa : 1; /* This board is EISA */ -#endif - - unchar raidnum; /* Uniquely identifies this HBA in a system */ - unchar notused; - - ushort ipad[247]; -}; - -/* Board config structure */ -struct eata_config { - ushort len; /* Number of bytes following this field */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar : 4, - tarena : 1, - mdpena : 1, - ocena : 1, - edis : 1; -#else - unchar edis : 1, /* Disable EATA interface after config command */ - ocena : 1, /* Overlapped Commands Enabled */ - mdpena : 1, /* Transfer all Modified Data Pointer Messages */ - tarena : 1, /* Target Mode Enabled for this controller */ - : 4; -#endif - unchar cpad[511]; -}; - -/* Returned status packet structure */ -struct mssp { -#if defined(__BIG_ENDIAN_BITFIELD) - unchar eoc : 1, - adapter_status : 7; -#else - unchar adapter_status : 7, /* State related to current command */ - eoc : 1; /* End Of Command (1 = command completed) */ -#endif - unchar target_status; /* SCSI status received after data transfer */ - unchar unused[2]; - u_int32_t inv_res_len; /* Number of bytes not transferred */ - u_int32_t cpp_index; /* Index of address set in cp */ - char mess[12]; -}; - -struct sg_list { - unsigned int address; /* Segment Address */ - unsigned int num_bytes; /* Segment Length */ -}; - -/* MailBox SCSI Command Packet */ -struct mscp { -#if defined(__BIG_ENDIAN_BITFIELD) - unchar din : 1, - dout : 1, - interp : 1, - : 1, - sg : 1, - reqsen :1, - init : 1, - sreset : 1; - unchar sense_len; - unchar unused[3]; - unchar : 7, - fwnest : 1; - unchar : 5, - hbaci : 1, - iat : 1, - phsunit : 1; - unchar channel : 3, - target : 5; - unchar one : 1, - dispri : 1, - luntar : 1, - lun : 5; -#else - unchar sreset :1, /* SCSI Bus Reset Signal should be asserted */ - init :1, /* Re-initialize controller and self test */ - reqsen :1, /* Transfer Request Sense Data to addr using DMA */ - sg :1, /* Use Scatter/Gather */ - :1, - interp :1, /* The controller interprets cp, not the target */ - dout :1, /* Direction of Transfer is Out (Host to Target) */ - din :1; /* Direction of Transfer is In (Target to Host) */ - unchar sense_len; /* Request Sense Length */ - unchar unused[3]; - unchar fwnest : 1, /* Send command to a component of an Array Group */ - : 7; - unchar phsunit : 1, /* Send to Target Physical Unit (bypass RAID) */ - iat : 1, /* Inhibit Address Translation */ - hbaci : 1, /* Inhibit HBA Caching for this command */ - : 5; - unchar target : 5, /* SCSI target ID */ - channel : 3; /* SCSI channel number */ - unchar lun : 5, /* SCSI logical unit number */ - luntar : 1, /* This cp is for Target (not LUN) */ - dispri : 1, /* Disconnect Privilege granted */ - one : 1; /* 1 */ -#endif - - unchar mess[3]; /* Massage to/from Target */ - unchar cdb[12]; /* Command Descriptor Block */ - u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ - u_int32_t cpp_index; /* Index of address to be returned in sp */ - u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ - u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ - u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ - - /* Additional fields begin here. */ - struct scsi_cmnd *SCpnt; - - /* All the cp structure is zero filled by queuecommand except the - following CP_TAIL_SIZE bytes, initialized by detect */ - dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ - struct sg_list *sglist; /* pointer to the allocated SG list */ -}; - -#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) - -struct hostdata { - struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ - unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ - unsigned int last_cp_used; /* Index of last mailbox used */ - unsigned int iocount; /* Total i/o done for this board */ - int board_number; /* Number of this board */ - char board_name[16]; /* Name of this board */ - int in_reset; /* True if board is doing a reset */ - int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ - int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If 1 redo i/o on target */ - unsigned int retries; /* Number of internal retries */ - unsigned long last_retried_pid; /* Pid of last retried command */ - unsigned char subversion; /* Bus type, either ISA or EISA/PCI */ - unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ - unsigned char is_pci; /* 1 is bus type is PCI */ - struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */ - struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */ - dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */ - struct mssp sp; /* Local copy of sp buffer */ -}; - -static struct Scsi_Host *sh[MAX_BOARDS]; -static const char *driver_name = "EATA"; -static char sha[MAX_BOARDS]; - -/* Initialize num_boards so that ihdlr can work while detect is in progress */ -static unsigned int num_boards = MAX_BOARDS; - -static unsigned long io_port[] = { - - /* Space for MAX_INT_PARAM ports usable while loading as a module */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, - - /* First ISA */ - 0x1f0, - - /* Space for MAX_PCI ports possibly reported by PCI_BIOS */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - - /* MAX_EISA ports */ - 0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88, - 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, - - /* Other (MAX_ISA - 1) ports */ - 0x170, 0x230, 0x330, - - /* End of list */ - 0x0 -}; - -/* Device is Big Endian */ -#define H2DEV(x) cpu_to_be32(x) -#define DEV2H(x) be32_to_cpu(x) -#define H2DEV16(x) cpu_to_be16(x) -#define DEV2H16(x) be16_to_cpu(x) - -/* But transfer orientation from the 16 bit data register is Little Endian */ -#define REG2H(x) le16_to_cpu(x) - -static irqreturn_t do_interrupt_handler(int, void *); -static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *, - unsigned int); -static int do_trace = 0; -static int setup_done = 0; -static int link_statistics; -static int ext_tran = 0; -static int rev_scan = 1; - -#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE) -static int tag_mode = TAG_SIMPLE; -#else -static int tag_mode = TAG_DISABLED; -#endif - -#if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS) -static int linked_comm = 1; -#else -static int linked_comm = 0; -#endif - -#if defined(CONFIG_SCSI_EATA_MAX_TAGS) -static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS; -#else -static int max_queue_depth = MAX_CMD_PER_LUN; -#endif - -#if defined(CONFIG_ISA) -static int isa_probe = 1; -#else -static int isa_probe = 0; -#endif - -#if defined(CONFIG_EISA) -static int eisa_probe = 1; -#else -static int eisa_probe = 0; -#endif - -#if defined(CONFIG_PCI) -static int pci_probe = 1; -#else -static int pci_probe = 0; -#endif - -#define MAX_INT_PARAM 10 -#define MAX_BOOT_OPTIONS_SIZE 256 -static char boot_options[MAX_BOOT_OPTIONS_SIZE]; - -#if defined(MODULE) -#include <linux/module.h> -#include <linux/moduleparam.h> - -module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); -MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option." - " Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\""); -MODULE_AUTHOR("Dario Ballabio"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("EATA/DMA SCSI Driver"); - -#endif - -static int eata2x_slave_configure(struct scsi_device *dev) -{ - int tqd, utqd; - char *tag_suffix, *link_suffix; - - utqd = MAX_CMD_PER_LUN; - tqd = max_queue_depth; - - if (TLDEV(dev->type) && dev->tagged_supported) { - if (tag_mode == TAG_SIMPLE) { - tag_suffix = ", simple tags"; - } else if (tag_mode == TAG_ORDERED) { - tag_suffix = ", ordered tags"; - } else { - tag_suffix = ", no tags"; - } - scsi_change_queue_depth(dev, tqd); - } else if (TLDEV(dev->type) && linked_comm) { - scsi_change_queue_depth(dev, tqd); - tag_suffix = ", untagged"; - } else { - scsi_change_queue_depth(dev, utqd); - tag_suffix = ""; - } - - if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2) - link_suffix = ", sorted"; - else if (TLDEV(dev->type)) - link_suffix = ", unsorted"; - else - link_suffix = ""; - - sdev_printk(KERN_INFO, dev, - "cmds/lun %d%s%s.\n", - dev->queue_depth, link_suffix, tag_suffix); - - return 0; -} - -static int wait_on_busy(unsigned long iobase, unsigned int loop) -{ - while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) { - udelay(1L); - if (--loop == 0) - return 1; - } - return 0; -} - -static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) -{ - unsigned char *byaddr; - unsigned long devaddr; - - if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) - return 1; - - if (addr) { - devaddr = H2DEV(addr); - byaddr = (unsigned char *)&devaddr; - outb(byaddr[3], iobase + REG_LOW); - outb(byaddr[2], iobase + REG_LM); - outb(byaddr[1], iobase + REG_MID); - outb(byaddr[0], iobase + REG_MSB); - } - - outb(cmd, iobase + REG_CMD); - return 0; -} - -static int read_pio(unsigned long iobase, ushort * start, ushort * end) -{ - unsigned int loop = MAXLOOP; - ushort *p; - - for (p = start; p <= end; p++) { - while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) { - udelay(1L); - if (--loop == 0) - return 1; - } - loop = MAXLOOP; - *p = REG2H(inw(iobase)); - } - - return 0; -} - -static struct pci_dev *get_pci_dev(unsigned long port_base) -{ -#if defined(CONFIG_PCI) - unsigned int addr; - struct pci_dev *dev = NULL; - - while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { - addr = pci_resource_start(dev, 0); - -#if defined(DEBUG_PCI_DETECT) - printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, dev->bus->number, dev->devfn, addr); -#endif - - /* we are in so much trouble for a pci hotplug system with this driver - * anyway, so doing this at least lets people unload the driver and not - * cause memory problems, but in general this is a bad thing to do (this - * driver needs to be converted to the proper PCI api someday... */ - pci_dev_put(dev); - if (addr + PCI_BASE_ADDRESS_0 == port_base) - return dev; - } -#endif /* end CONFIG_PCI */ - return NULL; -} - -static void enable_pci_ports(void) -{ -#if defined(CONFIG_PCI) - struct pci_dev *dev = NULL; - - while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { -#if defined(DEBUG_PCI_DETECT) - printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n", - driver_name, dev->bus->number, dev->devfn); -#endif - - if (pci_enable_device(dev)) - printk - ("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n", - driver_name, dev->bus->number, dev->devfn); - } - -#endif /* end CONFIG_PCI */ -} - -static int port_detect(unsigned long port_base, unsigned int j, - struct scsi_host_template *tpnt) -{ - unsigned char irq, dma_channel, subversion, i, is_pci = 0; - unsigned char protocol_rev; - struct eata_info info; - char *bus_type, dma_name[16]; - struct pci_dev *pdev; - /* Allowed DMA channels for ISA (0 indicates reserved) */ - unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; - struct Scsi_Host *shost; - struct hostdata *ha; - char name[16]; - - sprintf(name, "%s%d", driver_name, j); - - if (!request_region(port_base, REGION_SIZE, driver_name)) { -#if defined(DEBUG_DETECT) - printk("%s: address 0x%03lx in use, skipping probe.\n", name, - port_base); -#endif - goto fail; - } - - if (do_dma(port_base, 0, READ_CONFIG_PIO)) { -#if defined(DEBUG_DETECT) - printk("%s: detect, do_dma failed at 0x%03lx.\n", name, - port_base); -#endif - goto freelock; - } - - /* Read the info structure */ - if (read_pio(port_base, (ushort *) & info, (ushort *) & info.ipad[0])) { -#if defined(DEBUG_DETECT) - printk("%s: detect, read_pio failed at 0x%03lx.\n", name, - port_base); -#endif - goto freelock; - } - - info.data_len = DEV2H(info.data_len); - info.sign = DEV2H(info.sign); - info.cp_pad_len = DEV2H16(info.cp_pad_len); - info.cp_len = DEV2H(info.cp_len); - info.sp_len = DEV2H(info.sp_len); - info.scatt_size = DEV2H16(info.scatt_size); - info.queue_size = DEV2H16(info.queue_size); - - /* Check the controller "EATA" signature */ - if (info.sign != EATA_SIG_BE) { -#if defined(DEBUG_DETECT) - printk("%s: signature 0x%04x discarded.\n", name, info.sign); -#endif - goto freelock; - } - - if (info.data_len < EATA_2_0A_SIZE) { - printk - ("%s: config structure size (%d bytes) too short, detaching.\n", - name, info.data_len); - goto freelock; - } else if (info.data_len == EATA_2_0A_SIZE) - protocol_rev = 'A'; - else if (info.data_len == EATA_2_0B_SIZE) - protocol_rev = 'B'; - else - protocol_rev = 'C'; - - if (protocol_rev != 'A' && info.forcaddr) { - printk("%s: warning, port address has been forced.\n", name); - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } else if (port_base > MAX_EISA_ADDR - || (protocol_rev == 'C' && info.pci)) { - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } else if (port_base >= MIN_EISA_ADDR - || (protocol_rev == 'C' && info.eisa)) { - bus_type = "EISA"; - subversion = ESA; - } else if (protocol_rev == 'C' && !info.eisa && !info.pci) { - bus_type = "ISA"; - subversion = ISA; - } else if (port_base > MAX_ISA_ADDR) { - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } else { - bus_type = "ISA"; - subversion = ISA; - } - - if (!info.haaval || info.ata) { - printk - ("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", - name, port_base, bus_type, info.haaval, info.ata); - goto freelock; - } - - if (info.drqvld) { - if (subversion == ESA) - printk("%s: warning, weird %s board using DMA.\n", name, - bus_type); - - subversion = ISA; - dma_channel = dma_channel_table[3 - info.drqx]; - } else { - if (subversion == ISA) - printk("%s: warning, weird %s board not using DMA.\n", - name, bus_type); - - subversion = ESA; - dma_channel = NO_DMA; - } - - if (!info.dmasup) - printk("%s: warning, DMA protocol support not asserted.\n", - name); - - irq = info.irq; - - if (subversion == ESA && !info.irq_tr) - printk - ("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", - name, irq); - - if (is_pci) { - pdev = get_pci_dev(port_base); - if (!pdev) - printk - ("%s: warning, failed to get pci_dev structure.\n", - name); - } else - pdev = NULL; - - if (pdev && (irq != pdev->irq)) { - printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, - pdev->irq); - irq = pdev->irq; - } - - /* Board detected, allocate its IRQ */ - if (request_irq(irq, do_interrupt_handler, - (subversion == ESA) ? IRQF_SHARED : 0, - driver_name, (void *)&sha[j])) { - printk("%s: unable to allocate IRQ %u, detaching.\n", name, - irq); - goto freelock; - } - - if (subversion == ISA && request_dma(dma_channel, driver_name)) { - printk("%s: unable to allocate DMA channel %u, detaching.\n", - name, dma_channel); - goto freeirq; - } -#if defined(FORCE_CONFIG) - { - struct eata_config *cf; - dma_addr_t cf_dma_addr; - - cf = pci_zalloc_consistent(pdev, sizeof(struct eata_config), - &cf_dma_addr); - - if (!cf) { - printk - ("%s: config, pci_alloc_consistent failed, detaching.\n", - name); - goto freedma; - } - - /* Set board configuration */ - cf->len = (ushort) H2DEV16((ushort) 510); - cf->ocena = 1; - - if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { - printk - ("%s: busy timeout sending configuration, detaching.\n", - name); - pci_free_consistent(pdev, sizeof(struct eata_config), - cf, cf_dma_addr); - goto freedma; - } - - } -#endif - - sh[j] = shost = scsi_register(tpnt, sizeof(struct hostdata)); - if (shost == NULL) { - printk("%s: unable to register host, detaching.\n", name); - goto freedma; - } - - shost->io_port = port_base; - shost->unique_id = port_base; - shost->n_io_port = REGION_SIZE; - shost->dma_channel = dma_channel; - shost->irq = irq; - shost->sg_tablesize = (ushort) info.scatt_size; - shost->this_id = (ushort) info.host_addr[3]; - shost->can_queue = (ushort) info.queue_size; - shost->cmd_per_lun = MAX_CMD_PER_LUN; - - ha = (struct hostdata *)shost->hostdata; - - memset(ha, 0, sizeof(struct hostdata)); - ha->subversion = subversion; - ha->protocol_rev = protocol_rev; - ha->is_pci = is_pci; - ha->pdev = pdev; - ha->board_number = j; - - if (ha->subversion == ESA) - shost->unchecked_isa_dma = 0; - else { - unsigned long flags; - shost->unchecked_isa_dma = 1; - - flags = claim_dma_lock(); - disable_dma(dma_channel); - clear_dma_ff(dma_channel); - set_dma_mode(dma_channel, DMA_MODE_CASCADE); - enable_dma(dma_channel); - release_dma_lock(flags); - - } - - strcpy(ha->board_name, name); - - /* DPT PM2012 does not allow to detect sg_tablesize correctly */ - if (shost->sg_tablesize > MAX_SGLIST || shost->sg_tablesize < 2) { - printk("%s: detect, wrong n. of SG lists %d, fixed.\n", - ha->board_name, shost->sg_tablesize); - shost->sg_tablesize = MAX_SGLIST; - } - - /* DPT PM2012 does not allow to detect can_queue correctly */ - if (shost->can_queue > MAX_MAILBOXES || shost->can_queue < 2) { - printk("%s: detect, wrong n. of mbox %d, fixed.\n", - ha->board_name, shost->can_queue); - shost->can_queue = MAX_MAILBOXES; - } - - if (protocol_rev != 'A') { - if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL) - shost->max_channel = info.max_chan; - - if (info.max_id > 7 && info.max_id < MAX_TARGET) - shost->max_id = info.max_id + 1; - - if (info.large_sg && shost->sg_tablesize == MAX_SGLIST) - shost->sg_tablesize = MAX_LARGE_SGLIST; - } - - if (protocol_rev == 'C') { - if (info.max_lun > 7 && info.max_lun < MAX_LUN) - shost->max_lun = info.max_lun + 1; - } - - if (dma_channel == NO_DMA) - sprintf(dma_name, "%s", "BMST"); - else - sprintf(dma_name, "DMA %u", dma_channel); - - for (i = 0; i < shost->can_queue; i++) - ha->cp[i].cp_dma_addr = pci_map_single(ha->pdev, - &ha->cp[i], - sizeof(struct mscp), - PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < shost->can_queue; i++) { - size_t sz = shost->sg_tablesize *sizeof(struct sg_list); - gfp_t gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; - ha->cp[i].sglist = kmalloc(sz, gfp_mask); - if (!ha->cp[i].sglist) { - printk - ("%s: kmalloc SGlist failed, mbox %d, detaching.\n", - ha->board_name, i); - goto release; - } - } - - if (!(ha->sp_cpu_addr = pci_alloc_consistent(ha->pdev, - sizeof(struct mssp), - &ha->sp_dma_addr))) { - printk("%s: pci_alloc_consistent failed, detaching.\n", ha->board_name); - goto release; - } - - if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) - max_queue_depth = MAX_TAGGED_CMD_PER_LUN; - - if (max_queue_depth < MAX_CMD_PER_LUN) - max_queue_depth = MAX_CMD_PER_LUN; - - if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) - tag_mode = TAG_ORDERED; - - if (j == 0) { - printk - ("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n"); - printk - ("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, " - "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, - YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), - YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe), - YESNO(pci_probe)); - } - - printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n", - ha->board_name, ha->protocol_rev, bus_type, - (unsigned long)shost->io_port, shost->irq, dma_name, - shost->sg_tablesize, shost->can_queue); - - if (shost->max_id > 8 || shost->max_lun > 8) - printk - ("%s: wide SCSI support enabled, max_id %u, max_lun %llu.\n", - ha->board_name, shost->max_id, shost->max_lun); - - for (i = 0; i <= shost->max_channel; i++) - printk("%s: SCSI channel %u enabled, host target ID %d.\n", - ha->board_name, i, info.host_addr[3 - i]); - -#if defined(DEBUG_DETECT) - printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, " - "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version, - info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync, - info.second, info.data_len, info.cp_len, info.sp_len); - - if (protocol_rev == 'B' || protocol_rev == 'C') - printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, " - "large_sg %u, res1 %u.\n", name, info.isaena, - info.forcaddr, info.max_id, info.max_chan, info.large_sg, - info.res1); - - if (protocol_rev == 'C') - printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, " - "raidnum %u.\n", name, info.max_lun, info.m1, - info.idquest, info.pci, info.eisa, info.raidnum); -#endif - - if (ha->pdev) { - pci_set_master(ha->pdev); - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) - printk("%s: warning, pci_set_dma_mask failed.\n", - ha->board_name); - } - - return 1; - - freedma: - if (subversion == ISA) - free_dma(dma_channel); - freeirq: - free_irq(irq, &sha[j]); - freelock: - release_region(port_base, REGION_SIZE); - fail: - return 0; - - release: - eata2x_release(shost); - return 0; -} - -static void internal_setup(char *str, int *ints) -{ - int i, argc = ints[0]; - char *cur = str, *pc; - - if (argc > 0) { - if (argc > MAX_INT_PARAM) - argc = MAX_INT_PARAM; - - for (i = 0; i < argc; i++) - io_port[i] = ints[i + 1]; - - io_port[i] = 0; - setup_done = 1; - } - - while (cur && (pc = strchr(cur, ':'))) { - int val = 0, c = *++pc; - - if (c == 'n' || c == 'N') - val = 0; - else if (c == 'y' || c == 'Y') - val = 1; - else - val = (int)simple_strtoul(pc, NULL, 0); - - if (!strncmp(cur, "lc:", 3)) - linked_comm = val; - else if (!strncmp(cur, "tm:", 3)) - tag_mode = val; - else if (!strncmp(cur, "tc:", 3)) - tag_mode = val; - else if (!strncmp(cur, "mq:", 3)) - max_queue_depth = val; - else if (!strncmp(cur, "ls:", 3)) - link_statistics = val; - else if (!strncmp(cur, "et:", 3)) - ext_tran = val; - else if (!strncmp(cur, "rs:", 3)) - rev_scan = val; - else if (!strncmp(cur, "ip:", 3)) - isa_probe = val; - else if (!strncmp(cur, "ep:", 3)) - eisa_probe = val; - else if (!strncmp(cur, "pp:", 3)) - pci_probe = val; - - if ((cur = strchr(cur, ','))) - ++cur; - } - - return; -} - -static int option_setup(char *str) -{ - int ints[MAX_INT_PARAM]; - char *cur = str; - int i = 1; - - while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { - ints[i++] = simple_strtoul(cur, NULL, 0); - - if ((cur = strchr(cur, ',')) != NULL) - cur++; - } - - ints[0] = i - 1; - internal_setup(cur, ints); - return 1; -} - -static void add_pci_ports(void) -{ -#if defined(CONFIG_PCI) - unsigned int addr, k; - struct pci_dev *dev = NULL; - - for (k = 0; k < MAX_PCI; k++) { - - if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) - break; - - if (pci_enable_device(dev)) { -#if defined(DEBUG_PCI_DETECT) - printk - ("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", - driver_name, dev->bus->number, dev->devfn); -#endif - - continue; - } - - addr = pci_resource_start(dev, 0); - -#if defined(DEBUG_PCI_DETECT) - printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, k, dev->bus->number, dev->devfn, addr); -#endif - - /* Order addresses according to rev_scan value */ - io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] = - addr + PCI_BASE_ADDRESS_0; - } - - pci_dev_put(dev); -#endif /* end CONFIG_PCI */ -} - -static int eata2x_detect(struct scsi_host_template *tpnt) -{ - unsigned int j = 0, k; - - tpnt->proc_name = "eata2x"; - - if (strlen(boot_options)) - option_setup(boot_options); - -#if defined(MODULE) - /* io_port could have been modified when loading as a module */ - if (io_port[0] != SKIP) { - setup_done = 1; - io_port[MAX_INT_PARAM] = 0; - } -#endif - - for (k = MAX_INT_PARAM; io_port[k]; k++) - if (io_port[k] == SKIP) - continue; - else if (io_port[k] <= MAX_ISA_ADDR) { - if (!isa_probe) - io_port[k] = SKIP; - } else if (io_port[k] >= MIN_EISA_ADDR - && io_port[k] <= MAX_EISA_ADDR) { - if (!eisa_probe) - io_port[k] = SKIP; - } - - if (pci_probe) { - if (!setup_done) - add_pci_ports(); - else - enable_pci_ports(); - } - - for (k = 0; io_port[k]; k++) { - - if (io_port[k] == SKIP) - continue; - - if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) - j++; - } - - num_boards = j; - return j; -} - -static void map_dma(unsigned int i, struct hostdata *ha) -{ - unsigned int k, pci_dir; - int count; - struct scatterlist *sg; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (SCpnt->sense_buffer) - cpp->sense_addr = - H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); - - cpp->sense_len = SCSI_SENSE_BUFFERSIZE; - - if (!scsi_sg_count(SCpnt)) { - cpp->data_len = 0; - return; - } - - count = pci_map_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), - pci_dir); - BUG_ON(!count); - - scsi_for_each_sg(SCpnt, sg, count, k) { - cpp->sglist[k].address = H2DEV(sg_dma_address(sg)); - cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg)); - } - - cpp->sg = 1; - cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist, - scsi_sg_count(SCpnt) * - sizeof(struct sg_list), - pci_dir)); - cpp->data_len = H2DEV((scsi_sg_count(SCpnt) * sizeof(struct sg_list))); -} - -static void unmap_dma(unsigned int i, struct hostdata *ha) -{ - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - - if (scsi_sg_count(SCpnt)) - pci_unmap_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), - pci_dir); - - if (!DEV2H(cpp->data_len)) - pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_unmap_single(ha->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void sync_dma(unsigned int i, struct hostdata *ha) -{ - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single_for_cpu(ha->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), - PCI_DMA_FROMDEVICE); - - if (scsi_sg_count(SCpnt)) - pci_dma_sync_sg_for_cpu(ha->pdev, scsi_sglist(SCpnt), - scsi_sg_count(SCpnt), pci_dir); - - if (!DEV2H(cpp->data_len)) - pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_dma_sync_single_for_cpu(ha->pdev, - DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha) -{ - unsigned int k; - - static const unsigned char data_out_cmds[] = { - 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, - 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, - 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d - }; - - static const unsigned char data_none_cmds[] = { - 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, - 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 - }; - - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - - if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { - cpp->din = 1; - cpp->dout = 0; - return; - } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { - cpp->din = 0; - cpp->dout = 1; - return; - } else if (SCpnt->sc_data_direction == DMA_NONE) { - cpp->din = 0; - cpp->dout = 0; - return; - } - - if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL) - panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", - ha->board_name); - - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->dout = 1; - break; - } - - if ((cpp->din = !cpp->dout)) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->din = 0; - break; - } - -} - -static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, - void (*done) (struct scsi_cmnd *)) -{ - struct Scsi_Host *shost = SCpnt->device->host; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - unsigned int i, k; - struct mscp *cpp; - - if (SCpnt->host_scribble) - panic("%s: qcomm, SCpnt %p already active.\n", - ha->board_name, SCpnt); - - /* i is the mailbox number, look for the first free mailbox - starting from last_cp_used */ - i = ha->last_cp_used + 1; - - for (k = 0; k < shost->can_queue; k++, i++) { - if (i >= shost->can_queue) - i = 0; - if (ha->cp_stat[i] == FREE) { - ha->last_cp_used = i; - break; - } - } - - if (k == shost->can_queue) { - printk("%s: qcomm, no free mailbox.\n", ha->board_name); - return 1; - } - - /* Set pointer to control packet structure */ - cpp = &ha->cp[i]; - - memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); - - /* Set pointer to status packet structure, Big Endian format */ - cpp->sp_dma_addr = H2DEV(ha->sp_dma_addr); - - SCpnt->scsi_done = done; - cpp->cpp_index = i; - SCpnt->host_scribble = (unsigned char *)&cpp->cpp_index; - - if (do_trace) - scmd_printk(KERN_INFO, SCpnt, - "qcomm, mbox %d.\n", i); - - cpp->reqsen = 1; - cpp->dispri = 1; -#if 0 - if (SCpnt->device->type == TYPE_TAPE) - cpp->hbaci = 1; -#endif - cpp->one = 1; - cpp->channel = SCpnt->device->channel; - cpp->target = SCpnt->device->id; - cpp->lun = SCpnt->device->lun; - cpp->SCpnt = SCpnt; - memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - /* Use data transfer direction SCpnt->sc_data_direction */ - scsi_to_dev_dir(i, ha); - - /* Map DMA buffers and SG list */ - map_dma(i, ha); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) { - ha->cp_stat[i] = READY; - flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 0); - return 0; - } - - /* Send control packet to the board */ - if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { - unmap_dma(i, ha); - SCpnt->host_scribble = NULL; - scmd_printk(KERN_INFO, SCpnt, "qcomm, adapter busy.\n"); - return 1; - } - - ha->cp_stat[i] = IN_USE; - return 0; -} - -static DEF_SCSI_QCMD(eata2x_queuecommand) - -static int eata2x_eh_abort(struct scsi_cmnd *SCarg) -{ - struct Scsi_Host *shost = SCarg->device->host; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - unsigned int i; - - if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, "abort, cmd inactive.\n"); - return SUCCESS; - } - - i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_WARNING, SCarg, "abort, mbox %d.\n", i); - - if (i >= shost->can_queue) - panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name); - - if (wait_on_busy(shost->io_port, MAXLOOP)) { - printk("%s: abort, timeout error.\n", ha->board_name); - return FAILED; - } - - if (ha->cp_stat[i] == FREE) { - printk("%s: abort, mbox %d is free.\n", ha->board_name, i); - return SUCCESS; - } - - if (ha->cp_stat[i] == IN_USE) { - printk("%s: abort, mbox %d is in use.\n", ha->board_name, i); - - if (SCarg != ha->cp[i].SCpnt) - panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", - ha->board_name, i, SCarg, ha->cp[i].SCpnt); - - if (inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) - printk("%s: abort, mbox %d, interrupt pending.\n", - ha->board_name, i); - - return FAILED; - } - - if (ha->cp_stat[i] == IN_RESET) { - printk("%s: abort, mbox %d is in reset.\n", ha->board_name, i); - return FAILED; - } - - if (ha->cp_stat[i] == LOCKED) { - printk("%s: abort, mbox %d is locked.\n", ha->board_name, i); - return SUCCESS; - } - - if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { - unmap_dma(i, ha); - SCarg->result = DID_ABORT << 16; - SCarg->host_scribble = NULL; - ha->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", - ha->board_name, i); - SCarg->scsi_done(SCarg); - return SUCCESS; - } - - panic("%s: abort, mbox %d, invalid cp_stat.\n", ha->board_name, i); -} - -static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) -{ - unsigned int i, time, k, c, limit = 0; - struct scsi_cmnd *SCpnt; - struct Scsi_Host *shost = SCarg->device->host; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - - scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); - - spin_lock_irq(shost->host_lock); - - if (SCarg->host_scribble == NULL) - printk("%s: reset, inactive.\n", ha->board_name); - - if (ha->in_reset) { - printk("%s: reset, exit, already in reset.\n", ha->board_name); - spin_unlock_irq(shost->host_lock); - return FAILED; - } - - if (wait_on_busy(shost->io_port, MAXLOOP)) { - printk("%s: reset, exit, timeout error.\n", ha->board_name); - spin_unlock_irq(shost->host_lock); - return FAILED; - } - - ha->retries = 0; - - for (c = 0; c <= shost->max_channel; c++) - for (k = 0; k < shost->max_id; k++) { - ha->target_redo[k][c] = 1; - ha->target_to[k][c] = 0; - } - - for (i = 0; i < shost->can_queue; i++) { - - if (ha->cp_stat[i] == FREE) - continue; - - if (ha->cp_stat[i] == LOCKED) { - ha->cp_stat[i] = FREE; - printk("%s: reset, locked mbox %d forced free.\n", - ha->board_name, i); - continue; - } - - if (!(SCpnt = ha->cp[i].SCpnt)) - panic("%s: reset, mbox %d, SCpnt == NULL.\n", ha->board_name, i); - - if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { - ha->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting.\n", - ha->board_name, i); - } - - else { - ha->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset.\n", - ha->board_name, i); - } - - if (SCpnt->host_scribble == NULL) - panic("%s: reset, mbox %d, garbled SCpnt.\n", ha->board_name, i); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: reset, mbox %d, index mismatch.\n", ha->board_name, i); - - if (SCpnt->scsi_done == NULL) - panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", - ha->board_name, i); - } - - if (do_dma(shost->io_port, 0, RESET_PIO)) { - printk("%s: reset, cannot reset, timeout error.\n", ha->board_name); - spin_unlock_irq(shost->host_lock); - return FAILED; - } - - printk("%s: reset, board reset done, enabling interrupts.\n", ha->board_name); - -#if defined(DEBUG_RESET) - do_trace = 1; -#endif - - ha->in_reset = 1; - - spin_unlock_irq(shost->host_lock); - - /* FIXME: use a sleep instead */ - time = jiffies; - while ((jiffies - time) < (10 * HZ) && limit++ < 200000) - udelay(100L); - - spin_lock_irq(shost->host_lock); - - printk("%s: reset, interrupts disabled, loops %d.\n", ha->board_name, limit); - - for (i = 0; i < shost->can_queue; i++) { - - if (ha->cp_stat[i] == IN_RESET) { - SCpnt = ha->cp[i].SCpnt; - unmap_dma(i, ha); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; - - /* This mailbox is still waiting for its interrupt */ - ha->cp_stat[i] = LOCKED; - - printk - ("%s, reset, mbox %d locked, DID_RESET, done.\n", - ha->board_name, i); - } - - else if (ha->cp_stat[i] == ABORTING) { - SCpnt = ha->cp[i].SCpnt; - unmap_dma(i, ha); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; - - /* This mailbox was never queued to the adapter */ - ha->cp_stat[i] = FREE; - - printk - ("%s, reset, mbox %d aborting, DID_RESET, done.\n", - ha->board_name, i); - } - - else - /* Any other mailbox has already been set free by interrupt */ - continue; - - SCpnt->scsi_done(SCpnt); - } - - ha->in_reset = 0; - do_trace = 0; - - printk("%s: reset, exit.\n", ha->board_name); - - spin_unlock_irq(shost->host_lock); - return SUCCESS; -} - -int eata2x_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *dkinfo) -{ - unsigned int size = capacity; - - if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { - dkinfo[0] = 255; - dkinfo[1] = 63; - dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); - } -#if defined (DEBUG_GEOMETRY) - printk("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, - dkinfo[0], dkinfo[1], dkinfo[2]); -#endif - - return 0; -} - -static void sort(unsigned long sk[], unsigned int da[], unsigned int n, - unsigned int rev) -{ - unsigned int i, j, k, y; - unsigned long x; - - for (i = 0; i < n - 1; i++) { - k = i; - - for (j = k + 1; j < n; j++) - if (rev) { - if (sk[j] > sk[k]) - k = j; - } else { - if (sk[j] < sk[k]) - k = j; - } - - if (k != i) { - x = sk[k]; - sk[k] = sk[i]; - sk[i] = x; - y = da[k]; - da[k] = da[i]; - da[i] = y; - } - } - - return; -} - -static int reorder(struct hostdata *ha, unsigned long cursec, - unsigned int ihdlr, unsigned int il[], unsigned int n_ready) -{ - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n; - unsigned int rev = 0, s = 1, r = 1; - unsigned int input_only = 1, overlap = 0; - unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; - unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0; - unsigned long ioseek = 0; - - static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; - static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; - static unsigned int readysorted = 0, revcount = 0; - static unsigned long seeksorted = 0, seeknosort = 0; - - if (link_statistics && !(++flushcount % link_statistics)) - printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d" - " av %ldK as %ldK.\n", flushcount, batchcount, - inputcount, ovlcount, readycount, readysorted, sortcount, - revcount, seeknosort / (readycount + 1), - seeksorted / (readycount + 1)); - - if (n_ready <= 1) - return 0; - - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - - if (!cpp->din) - input_only = 0; - - if (blk_rq_pos(SCpnt->request) < minsec) - minsec = blk_rq_pos(SCpnt->request); - if (blk_rq_pos(SCpnt->request) > maxsec) - maxsec = blk_rq_pos(SCpnt->request); - - sl[n] = blk_rq_pos(SCpnt->request); - ioseek += blk_rq_sectors(SCpnt->request); - - if (!n) - continue; - - if (sl[n] < sl[n - 1]) - s = 0; - if (sl[n] > sl[n - 1]) - r = 0; - - if (link_statistics) { - if (sl[n] > sl[n - 1]) - seek += sl[n] - sl[n - 1]; - else - seek += sl[n - 1] - sl[n]; - } - - } - - if (link_statistics) { - if (cursec > sl[0]) - seek += cursec - sl[0]; - else - seek += sl[0] - cursec; - } - - if (cursec > ((maxsec + minsec) / 2)) - rev = 1; - - if (ioseek > ((maxsec - minsec) / 2)) - rev = 0; - - if (!((rev && r) || (!rev && s))) - sort(sl, il, n_ready, rev); - - if (!input_only) - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - ll[n] = blk_rq_sectors(SCpnt->request); - pl[n] = SCpnt->serial_number; - - if (!n) - continue; - - if ((sl[n] == sl[n - 1]) - || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) - || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) - overlap = 1; - } - - if (overlap) - sort(pl, il, n_ready, 0); - - if (link_statistics) { - if (cursec > sl[0]) - iseek = cursec - sl[0]; - else - iseek = sl[0] - cursec; - batchcount++; - readycount += n_ready; - seeknosort += seek / 1024; - if (input_only) - inputcount++; - if (overlap) { - ovlcount++; - seeksorted += iseek / 1024; - } else - seeksorted += (iseek + maxsec - minsec) / 1024; - if (rev && !r) { - revcount++; - readysorted += n_ready; - } - if (!rev && !s) { - sortcount++; - readysorted += n_ready; - } - } -#if defined(DEBUG_LINKED_COMMANDS) - if (link_statistics && (overlap || !(flushcount % link_statistics))) - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - scmd_printk(KERN_INFO, SCpnt, - "%s mb %d fc %d nr %d sec %ld ns %u" - " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", - (ihdlr ? "ihdlr" : "qcomm"), - k, flushcount, - n_ready, blk_rq_pos(SCpnt->request), - blk_rq_sectors(SCpnt->request), cursec, YESNO(s), - YESNO(r), YESNO(rev), YESNO(input_only), - YESNO(overlap), cpp->din); - } -#endif - return overlap; -} - -static void flush_dev(struct scsi_device *dev, unsigned long cursec, - struct hostdata *ha, unsigned int ihdlr) -{ - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; - - for (k = 0; k < dev->host->can_queue; k++) { - - if (ha->cp_stat[k] != READY && ha->cp_stat[k] != IN_USE) - continue; - - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - - if (SCpnt->device != dev) - continue; - - if (ha->cp_stat[k] == IN_USE) - return; - - il[n_ready++] = k; - } - - if (reorder(ha, cursec, ihdlr, il, n_ready)) - n_ready = 1; - - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - - if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { - scmd_printk(KERN_INFO, SCpnt, - "%s, mbox %d, adapter" - " busy, will abort.\n", - (ihdlr ? "ihdlr" : "qcomm"), - k); - ha->cp_stat[k] = ABORTING; - continue; - } - - ha->cp_stat[k] = IN_USE; - } -} - -static irqreturn_t ihdlr(struct Scsi_Host *shost) -{ - struct scsi_cmnd *SCpnt; - unsigned int i, k, c, status, tstatus, reg; - struct mssp *spp; - struct mscp *cpp; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - int irq = shost->irq; - - /* Check if this board need to be serviced */ - if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) - goto none; - - ha->iocount++; - - if (do_trace) - printk("%s: ihdlr, enter, irq %d, count %d.\n", ha->board_name, irq, - ha->iocount); - - /* Check if this board is still busy */ - if (wait_on_busy(shost->io_port, 20 * MAXLOOP)) { - reg = inb(shost->io_port + REG_STATUS); - printk - ("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", - ha->board_name, irq, reg, ha->iocount); - goto none; - } - - spp = &ha->sp; - - /* Make a local copy just before clearing the interrupt indication */ - memcpy(spp, ha->sp_cpu_addr, sizeof(struct mssp)); - - /* Clear the completion flag and cp pointer on the dynamic copy of sp */ - memset(ha->sp_cpu_addr, 0, sizeof(struct mssp)); - - /* Read the status register to clear the interrupt indication */ - reg = inb(shost->io_port + REG_STATUS); - -#if defined (DEBUG_INTERRUPT) - { - unsigned char *bytesp; - int cnt; - bytesp = (unsigned char *)spp; - if (ha->iocount < 200) { - printk("sp[] ="); - for (cnt = 0; cnt < 15; cnt++) - printk(" 0x%x", bytesp[cnt]); - printk("\n"); - } - } -#endif - - /* Reject any sp with supspect data */ - if (spp->eoc == 0 && ha->iocount > 1) - printk - ("%s: ihdlr, spp->eoc == 0, irq %d, reg 0x%x, count %d.\n", - ha->board_name, irq, reg, ha->iocount); - if (spp->cpp_index < 0 || spp->cpp_index >= shost->can_queue) - printk - ("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n", - ha->board_name, spp->cpp_index, irq, reg, ha->iocount); - if (spp->eoc == 0 || spp->cpp_index < 0 - || spp->cpp_index >= shost->can_queue) - goto handled; - - /* Find the mailbox to be serviced on this board */ - i = spp->cpp_index; - - cpp = &(ha->cp[i]); - -#if defined(DEBUG_GENERATE_ABORTS) - if ((ha->iocount > 500) && ((ha->iocount % 500) < 3)) - goto handled; -#endif - - if (ha->cp_stat[i] == IGNORE) { - ha->cp_stat[i] = FREE; - goto handled; - } else if (ha->cp_stat[i] == LOCKED) { - ha->cp_stat[i] = FREE; - printk("%s: ihdlr, mbox %d unlocked, count %d.\n", ha->board_name, i, - ha->iocount); - goto handled; - } else if (ha->cp_stat[i] == FREE) { - printk("%s: ihdlr, mbox %d is free, count %d.\n", ha->board_name, i, - ha->iocount); - goto handled; - } else if (ha->cp_stat[i] == IN_RESET) - printk("%s: ihdlr, mbox %d is in reset.\n", ha->board_name, i); - else if (ha->cp_stat[i] != IN_USE) - panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", - ha->board_name, i, ha->cp_stat[i]); - - ha->cp_stat[i] = FREE; - SCpnt = cpp->SCpnt; - - if (SCpnt == NULL) - panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i); - - if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", ha->board_name, - i, SCpnt); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, index mismatch %d.\n", - ha->board_name, i, - *(unsigned int *)SCpnt->host_scribble); - - sync_dma(i, ha); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 1); - - tstatus = status_byte(spp->target_status); - -#if defined(DEBUG_GENERATE_ERRORS) - if ((ha->iocount > 500) && ((ha->iocount % 200) < 2)) - spp->adapter_status = 0x01; -#endif - - switch (spp->adapter_status) { - case ASOK: /* status OK */ - - /* Forces a reset if a disk drive keeps returning BUSY */ - if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) - status = DID_ERROR << 16; - - /* If there was a bus reset, redo operation on each target */ - else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK - && ha->target_redo[SCpnt->device->id][SCpnt-> - device-> - channel]) - status = DID_BUS_BUSY << 16; - - /* Works around a flaw in scsi.c */ - else if (tstatus == CHECK_CONDITION - && SCpnt->device->type == TYPE_DISK - && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR) - status = DID_BUS_BUSY << 16; - - else - status = DID_OK << 16; - - if (tstatus == GOOD) - ha->target_redo[SCpnt->device->id][SCpnt->device-> - channel] = 0; - - if (spp->target_status && SCpnt->device->type == TYPE_DISK && - (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 && - (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) - printk("%s: ihdlr, target %d.%d:%d, " - "target_status 0x%x, sense key 0x%x.\n", - ha->board_name, - SCpnt->device->channel, SCpnt->device->id, - (u8)SCpnt->device->lun, - spp->target_status, SCpnt->sense_buffer[2]); - - ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; - - if (ha->last_retried_pid == SCpnt->serial_number) - ha->retries = 0; - - break; - case ASST: /* Selection Time Out */ - case 0x02: /* Command Time Out */ - - if (ha->target_to[SCpnt->device->id][SCpnt->device->channel] > 1) - status = DID_ERROR << 16; - else { - status = DID_TIME_OUT << 16; - ha->target_to[SCpnt->device->id][SCpnt->device-> - channel]++; - } - - break; - - /* Perform a limited number of internal retries */ - case 0x03: /* SCSI Bus Reset Received */ - case 0x04: /* Initial Controller Power-up */ - - for (c = 0; c <= shost->max_channel; c++) - for (k = 0; k < shost->max_id; k++) - ha->target_redo[k][c] = 1; - - if (SCpnt->device->type != TYPE_TAPE - && ha->retries < MAX_INTERNAL_RETRIES) { - -#if defined(DID_SOFT_ERROR) - status = DID_SOFT_ERROR << 16; -#else - status = DID_BUS_BUSY << 16; -#endif - - ha->retries++; - ha->last_retried_pid = SCpnt->serial_number; - } else - status = DID_ERROR << 16; - - break; - case 0x05: /* Unexpected Bus Phase */ - case 0x06: /* Unexpected Bus Free */ - case 0x07: /* Bus Parity Error */ - case 0x08: /* SCSI Hung */ - case 0x09: /* Unexpected Message Reject */ - case 0x0a: /* SCSI Bus Reset Stuck */ - case 0x0b: /* Auto Request-Sense Failed */ - case 0x0c: /* Controller Ram Parity Error */ - default: - status = DID_ERROR << 16; - break; - } - - SCpnt->result = status | spp->target_status; - -#if defined(DEBUG_INTERRUPT) - if (SCpnt->result || do_trace) -#else - if ((spp->adapter_status != ASOK && ha->iocount > 1000) || - (spp->adapter_status != ASOK && - spp->adapter_status != ASST && ha->iocount <= 1000) || - do_trace || msg_byte(spp->target_status)) -#endif - scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x," - " reg 0x%x, count %d.\n", - i, spp->adapter_status, spp->target_status, - reg, ha->iocount); - - unmap_dma(i, ha); - - /* Set the command state to inactive */ - SCpnt->host_scribble = NULL; - - SCpnt->scsi_done(SCpnt); - - if (do_trace) - printk("%s: ihdlr, exit, irq %d, count %d.\n", ha->board_name, - irq, ha->iocount); - - handled: - return IRQ_HANDLED; - none: - return IRQ_NONE; -} - -static irqreturn_t do_interrupt_handler(int dummy, void *shap) -{ - struct Scsi_Host *shost; - unsigned int j; - unsigned long spin_flags; - irqreturn_t ret; - - /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) - return IRQ_NONE; - shost = sh[j]; - - spin_lock_irqsave(shost->host_lock, spin_flags); - ret = ihdlr(shost); - spin_unlock_irqrestore(shost->host_lock, spin_flags); - return ret; -} - -static int eata2x_release(struct Scsi_Host *shost) -{ - struct hostdata *ha = (struct hostdata *)shost->hostdata; - unsigned int i; - - for (i = 0; i < shost->can_queue; i++) - kfree((&ha->cp[i])->sglist); - - for (i = 0; i < shost->can_queue; i++) - pci_unmap_single(ha->pdev, ha->cp[i].cp_dma_addr, - sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); - - if (ha->sp_cpu_addr) - pci_free_consistent(ha->pdev, sizeof(struct mssp), - ha->sp_cpu_addr, ha->sp_dma_addr); - - free_irq(shost->irq, &sha[ha->board_number]); - - if (shost->dma_channel != NO_DMA) - free_dma(shost->dma_channel); - - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -#include "scsi_module.c" - -#ifndef MODULE -__setup("eata=", option_setup); -#endif /* end MODULE */ diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h deleted file mode 100644 index 1a396c5e7f73..000000000000 --- a/drivers/scsi/eata_generic.h +++ /dev/null @@ -1,401 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/******************************************************** -* Header file for eata_dma.c and eata_pio.c * -* Linux EATA SCSI drivers * -* (c) 1993-96 Michael Neuffer * -* mike@i-Connect.Net * -* neuffer@mail.uni-mainz.de * -********************************************************* -* last change: 96/08/14 * -********************************************************/ - - -#ifndef _EATA_GENERIC_H -#define _EATA_GENERIC_H - - - -/********************************************* - * Misc. definitions * - *********************************************/ - -#define R_LIMIT 0x20000 - -#define MAXISA 4 -#define MAXEISA 16 -#define MAXPCI 16 -#define MAXIRQ 16 -#define MAXTARGET 16 -#define MAXCHANNEL 3 - -#define IS_ISA 'I' -#define IS_EISA 'E' -#define IS_PCI 'P' - -#define BROKEN_INQUIRY 1 - -#define BUSMASTER 0xff -#define PIO 0xfe - -#define EATA_SIGNATURE 0x45415441 /* BIG ENDIAN coded "EATA" sig. */ - -#define DPT_ID1 0x12 -#define DPT_ID2 0x14 - -#define ATT_ID1 0x06 -#define ATT_ID2 0x94 -#define ATT_ID3 0x0 - -#define NEC_ID1 0x38 -#define NEC_ID2 0xa3 -#define NEC_ID3 0x82 - - -#define EATA_CP_SIZE 44 - -#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */ -#define MAX_METHOD_2 16 /* Max Devices For Method 2 */ -#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */ - -#define SG_SIZE 64 -#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ - -#define UPPER_DEVICE_QUEUE_LIMIT 64 /* The limit we have to set for the - * device queue to keep the broken - * midlevel SCSI code from producing - * bogus timeouts - */ - -#define TYPE_DISK_QUEUE 16 -#define TYPE_TAPE_QUEUE 4 -#define TYPE_ROM_QUEUE 4 -#define TYPE_OTHER_QUEUE 2 - -#define FREE 0 -#define OK 0 -#define NO_TIMEOUT 0 -#define USED 1 -#define TIMEOUT 2 -#define RESET 4 -#define LOCKED 8 -#define ABORTED 16 - -#define READ 0 -#define WRITE 1 -#define OTHER 2 - -#define HD(cmd) ((hostdata *)&(cmd->device->host->hostdata)) -#define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble)) -#define SD(host) ((hostdata *)&(host->hostdata)) - -/*********************************************** - * EATA Command & Register definitions * - ***********************************************/ -#define PCI_REG_DPTconfig 0x40 -#define PCI_REG_PumpModeAddress 0x44 -#define PCI_REG_PumpModeData 0x48 -#define PCI_REG_ConfigParam1 0x50 -#define PCI_REG_ConfigParam2 0x54 - - -#define EATA_CMD_PIO_SETUPTEST 0xc6 -#define EATA_CMD_PIO_READ_CONFIG 0xf0 -#define EATA_CMD_PIO_SET_CONFIG 0xf1 -#define EATA_CMD_PIO_SEND_CP 0xf2 -#define EATA_CMD_PIO_RECEIVE_SP 0xf3 -#define EATA_CMD_PIO_TRUNC 0xf4 - -#define EATA_CMD_RESET 0xf9 -#define EATA_CMD_IMMEDIATE 0xfa - -#define EATA_CMD_DMA_READ_CONFIG 0xfd -#define EATA_CMD_DMA_SET_CONFIG 0xfe -#define EATA_CMD_DMA_SEND_CP 0xff - -#define ECS_EMULATE_SENSE 0xd4 - -#define EATA_GENERIC_ABORT 0x00 -#define EATA_SPECIFIC_RESET 0x01 -#define EATA_BUS_RESET 0x02 -#define EATA_SPECIFIC_ABORT 0x03 -#define EATA_QUIET_INTR 0x04 -#define EATA_COLD_BOOT_HBA 0x06 /* Only as a last resort */ -#define EATA_FORCE_IO 0x07 - -#define HA_CTRLREG 0x206 /* control register for HBA */ -#define HA_CTRL_DISINT 0x02 /* CTRLREG: disable interrupts */ -#define HA_CTRL_RESCPU 0x04 /* CTRLREG: reset processor */ -#define HA_CTRL_8HEADS 0x08 /* CTRLREG: set for drives with* - * >=8 heads (WD1003 rudimentary :-) */ - -#define HA_WCOMMAND 0x07 /* command register offset */ -#define HA_WIFC 0x06 /* immediate command offset */ -#define HA_WCODE 0x05 -#define HA_WCODE2 0x04 -#define HA_WDMAADDR 0x02 /* DMA address LSB offset */ -#define HA_RAUXSTAT 0x08 /* aux status register offset*/ -#define HA_RSTATUS 0x07 /* status register offset */ -#define HA_RDATA 0x00 /* data register (16bit) */ -#define HA_WDATA 0x00 /* data register (16bit) */ - -#define HA_ABUSY 0x01 /* aux busy bit */ -#define HA_AIRQ 0x02 /* aux IRQ pending bit */ -#define HA_SERROR 0x01 /* pr. command ended in error*/ -#define HA_SMORE 0x02 /* more data soon to come */ -#define HA_SCORR 0x04 /* data corrected */ -#define HA_SDRQ 0x08 /* data request active */ -#define HA_SSC 0x10 /* seek complete */ -#define HA_SFAULT 0x20 /* write fault */ -#define HA_SREADY 0x40 /* drive ready */ -#define HA_SBUSY 0x80 /* drive busy */ -#define HA_SDRDY HA_SSC+HA_SREADY+HA_SDRQ - -/********************************************** - * Message definitions * - **********************************************/ - -#define HA_NO_ERROR 0x00 /* No Error */ -#define HA_ERR_SEL_TO 0x01 /* Selection Timeout */ -#define HA_ERR_CMD_TO 0x02 /* Command Timeout */ -#define HA_BUS_RESET 0x03 /* SCSI Bus Reset Received */ -#define HA_INIT_POWERUP 0x04 /* Initial Controller Power-up */ -#define HA_UNX_BUSPHASE 0x05 /* Unexpected Bus Phase */ -#define HA_UNX_BUS_FREE 0x06 /* Unexpected Bus Free */ -#define HA_BUS_PARITY 0x07 /* Bus Parity Error */ -#define HA_SCSI_HUNG 0x08 /* SCSI Hung */ -#define HA_UNX_MSGRJCT 0x09 /* Unexpected Message Rejected */ -#define HA_RESET_STUCK 0x0a /* SCSI Bus Reset Stuck */ -#define HA_RSENSE_FAIL 0x0b /* Auto Request-Sense Failed */ -#define HA_PARITY_ERR 0x0c /* Controller Ram Parity Error */ -#define HA_CP_ABORT_NA 0x0d /* Abort Message sent to non-active cmd */ -#define HA_CP_ABORTED 0x0e /* Abort Message sent to active cmd */ -#define HA_CP_RESET_NA 0x0f /* Reset Message sent to non-active cmd */ -#define HA_CP_RESET 0x10 /* Reset Message sent to active cmd */ -#define HA_ECC_ERR 0x11 /* Controller Ram ECC Error */ -#define HA_PCI_PARITY 0x12 /* PCI Parity Error */ -#define HA_PCI_MABORT 0x13 /* PCI Master Abort */ -#define HA_PCI_TABORT 0x14 /* PCI Target Abort */ -#define HA_PCI_STABORT 0x15 /* PCI Signaled Target Abort */ - -/********************************************** - * Other definitions * - **********************************************/ - -struct reg_bit { /* reading this one will clear the interrupt */ - __u8 error:1; /* previous command ended in an error */ - __u8 more:1; /* more DATA coming soon, poll BSY & DRQ (PIO) */ - __u8 corr:1; /* data read was successfully corrected with ECC*/ - __u8 drq:1; /* data request active */ - __u8 sc:1; /* seek complete */ - __u8 fault:1; /* write fault */ - __u8 ready:1; /* drive ready */ - __u8 busy:1; /* controller busy */ -}; - -struct reg_abit { /* reading this won't clear the interrupt */ - __u8 abusy:1; /* auxiliary busy */ - __u8 irq:1; /* set when drive interrupt is asserted */ - __u8 dummy:6; -}; - -struct eata_register { /* EATA register set */ - __u8 data_reg[2]; /* R, couldn't figure this one out */ - __u8 cp_addr[4]; /* W, CP address register */ - union { - __u8 command; /* W, command code: [read|set] conf, send CP*/ - struct reg_bit status; /* R, see register_bit1 */ - __u8 statusbyte; - } ovr; - struct reg_abit aux_stat; /* R, see register_bit2 */ -}; - -struct get_conf { /* Read Configuration Array */ - __u32 len; /* Should return 0x22, 0x24, etc */ - __u32 signature; /* Signature MUST be "EATA" */ - __u8 version2:4, - version:4; /* EATA Version level */ - __u8 OCS_enabled:1, /* Overlap Command Support enabled */ - TAR_support:1, /* SCSI Target Mode supported */ - TRNXFR:1, /* Truncate Transfer Cmd not necessary * - * Only used in PIO Mode */ - MORE_support:1, /* MORE supported (only PIO Mode) */ - DMA_support:1, /* DMA supported Driver uses only * - * this mode */ - DMA_valid:1, /* DRQ value in Byte 30 is valid */ - ATA:1, /* ATA device connected (not supported) */ - HAA_valid:1; /* Hostadapter Address is valid */ - - __u16 cppadlen; /* Number of pad bytes send after CD data * - * set to zero for DMA commands */ - __u8 scsi_id[4]; /* SCSI ID of controller 2-0 Byte 0 res. * - * if not, zero is returned */ - __u32 cplen; /* CP length: number of valid cp bytes */ - __u32 splen; /* Number of bytes returned after * - * Receive SP command */ - __u16 queuesiz; /* max number of queueable CPs */ - __u16 dummy; - __u16 SGsiz; /* max number of SG table entries */ - __u8 IRQ:4, /* IRQ used this HA */ - IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */ - SECOND:1, /* This is a secondary controller */ - DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */ - __u8 sync; /* device at ID 7 tru 0 is running in * - * synchronous mode, this will disappear */ - __u8 DSBLE:1, /* ISA i/o addressing is disabled */ - FORCADR:1, /* i/o address has been forced */ - SG_64K:1, - SG_UAE:1, - :4; - __u8 MAX_ID:5, /* Max number of SCSI target IDs */ - MAX_CHAN:3; /* Number of SCSI busses on HBA */ - __u8 MAX_LUN; /* Max number of LUNs */ - __u8 :3, - AUTOTRM:1, - M1_inst:1, - ID_qest:1, /* Raidnum ID is questionable */ - is_PCI:1, /* HBA is PCI */ - is_EISA:1; /* HBA is EISA */ - __u8 RAIDNUM; /* unique HBA identifier */ - __u8 unused[474]; -}; - -struct eata_sg_list -{ - __u32 data; - __u32 len; -}; - -struct eata_ccb { /* Send Command Packet structure */ - - __u8 SCSI_Reset:1, /* Cause a SCSI Bus reset on the cmd */ - HBA_Init:1, /* Cause Controller to reinitialize */ - Auto_Req_Sen:1, /* Do Auto Request Sense on errors */ - scatter:1, /* Data Ptr points to a SG Packet */ - Resrvd:1, /* RFU */ - Interpret:1, /* Interpret the SCSI cdb of own use */ - DataOut:1, /* Data Out phase with command */ - DataIn:1; /* Data In phase with command */ - __u8 reqlen; /* Request Sense Length * - * Valid if Auto_Req_Sen=1 */ - __u8 unused[3]; - __u8 FWNEST:1, /* send cmd to phys RAID component */ - unused2:7; - __u8 Phsunit:1, /* physical unit on mirrored pair */ - I_AT:1, /* inhibit address translation */ - I_HBA_C:1, /* HBA inhibit caching */ - unused3:5; - - __u8 cp_id:5, /* SCSI Device ID of target */ - cp_channel:3; /* SCSI Channel # of HBA */ - __u8 cp_lun:3, - :2, - cp_luntar:1, /* CP is for target ROUTINE */ - cp_dispri:1, /* Grant disconnect privilege */ - cp_identify:1; /* Always TRUE */ - __u8 cp_msg1; /* Message bytes 0-3 */ - __u8 cp_msg2; - __u8 cp_msg3; - __u8 cp_cdb[12]; /* Command Descriptor Block */ - __u32 cp_datalen; /* Data Transfer Length * - * If scatter=1 len of sg package */ - void *cp_viraddr; /* address of this ccb */ - __u32 cp_dataDMA; /* Data Address, if scatter=1 * - * address of scatter packet */ - __u32 cp_statDMA; /* address for Status Packet */ - __u32 cp_reqDMA; /* Request Sense Address, used if * - * CP command ends with error */ - /* Additional CP info begins here */ - __u32 timestamp; /* Needed to measure command latency */ - __u32 timeout; - __u8 sizeindex; - __u8 rw_latency; - __u8 retries; - __u8 status; /* status of this queueslot */ - struct scsi_cmnd *cmd; /* address of cmd */ - struct eata_sg_list *sg_list; -}; - - -struct eata_sp { - __u8 hba_stat:7, /* HBA status */ - EOC:1; /* True if command finished */ - __u8 scsi_stat; /* Target SCSI status */ - __u8 reserved[2]; - __u32 residue_len; /* Number of bytes not transferred */ - struct eata_ccb *ccb; /* Address set in COMMAND PACKET */ - __u8 msg[12]; -}; - -typedef struct hstd { - __u8 vendor[9]; - __u8 name[18]; - __u8 revision[6]; - __u8 EATA_revision; - __u32 firmware_revision; - __u8 HBA_number; - __u8 bustype; /* bustype of HBA */ - __u8 channel; /* # of avail. scsi channels */ - __u8 state; /* state of HBA */ - __u8 primary; /* true if primary */ - __u8 more_support:1, /* HBA supports MORE flag */ - immediate_support:1, /* HBA supports IMMEDIATE CMDs*/ - broken_INQUIRY:1; /* This is an EISA HBA with * - * broken INQUIRY */ - __u8 do_latency; /* Latency measurement flag */ - __u32 reads[13]; - __u32 writes[13]; - __u32 reads_lat[12][4]; - __u32 writes_lat[12][4]; - __u32 all_lat[4]; - __u8 resetlevel[MAXCHANNEL]; - __u32 last_ccb; /* Last used ccb */ - __u32 cplen; /* size of CP in words */ - __u16 cppadlen; /* pad length of cp in words */ - __u16 queuesize; - __u16 sgsize; /* # of entries in the SG list*/ - __u16 devflags; /* bits set for detected devices */ - __u8 hostid; /* SCSI ID of HBA */ - __u8 moresupport; /* HBA supports MORE flag */ - struct Scsi_Host *next; - struct Scsi_Host *prev; - struct pci_dev *pdev; /* PCI device or NULL for non PCI */ - struct eata_sp sp; /* status packet */ - struct eata_ccb ccb[0]; /* ccb array begins here */ -}hostdata; - -/* structure for max. 2 emulated drives */ -struct drive_geom_emul { - __u8 trans; /* translation flag 1=transl */ - __u8 channel; /* SCSI channel number */ - __u8 HBA; /* HBA number (prim/sec) */ - __u8 id; /* drive id */ - __u8 lun; /* drive lun */ - __u32 heads; /* number of heads */ - __u32 sectors; /* number of sectors */ - __u32 cylinder; /* number of cylinders */ -}; - -struct geom_emul { - __u8 bios_drives; /* number of emulated drives */ - struct drive_geom_emul drv[2]; /* drive structures */ -}; - -#endif /* _EATA_GENERIC_H */ - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * tab-width: 8 - * End: - */ diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c deleted file mode 100644 index 4299fa485622..000000000000 --- a/drivers/scsi/eata_pio.c +++ /dev/null @@ -1,966 +0,0 @@ -/************************************************************ - * * - * Linux EATA SCSI PIO driver * - * * - * based on the CAM document CAM/89-004 rev. 2.0c, * - * DPT's driver kit, some internal documents and source, * - * and several other Linux scsi drivers and kernel docs. * - * * - * The driver currently: * - * -supports all EATA-PIO boards * - * -only supports DASD devices * - * * - * (c)1993-96 Michael Neuffer, Alfred Arnold * - * neuffer@goofy.zdv.uni-mainz.de * - * a.arnold@kfa-juelich.de * - * * - * Updated 2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> for * - * Linux 2.5.x and the newer locking and error handling * - * * - * This program is free software; you can redistribute it * - * and/or modify it under the terms of the GNU General * - * Public License as published by the Free Software * - * Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the * - * implied warranty of MERCHANTABILITY or FITNESS FOR A * - * PARTICULAR PURPOSE. See the GNU General Public License * - * for more details. * - * * - * You should have received a copy of the GNU General * - * Public License along with this kernel; if not, write to * - * the Free Software Foundation, Inc., 675 Mass Ave, * - * Cambridge, MA 02139, USA. * - * * - * For the avoidance of doubt the "preferred form" of this * - * code is one which is in an open non patent encumbered * - * format. Where cryptographic key signing forms part of * - * the process of creating an executable the information * - * including keys needed to generate an equivalently * - * functional executable are deemed to be part of the * - * source code are deemed to be part of the source code. * - * * - ************************************************************ - * last change: 2002/11/02 OS: Linux 2.5.45 * - ************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/pci.h> -#include <linux/proc_fs.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/spinlock.h> -#include <linux/delay.h> - -#include <asm/io.h> - -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_host.h> - -#include "eata_generic.h" -#include "eata_pio.h" - - -static unsigned int ISAbases[MAXISA] = { - 0x1F0, 0x170, 0x330, 0x230 -}; - -static unsigned int ISAirqs[MAXISA] = { - 14, 12, 15, 11 -}; - -static unsigned char EISAbases[] = { - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 -}; - -static unsigned int registered_HBAs; -static struct Scsi_Host *last_HBA; -static struct Scsi_Host *first_HBA; -static unsigned char reg_IRQ[16]; -static unsigned char reg_IRQL[16]; -static unsigned long int_counter; -static unsigned long queue_counter; - -static struct scsi_host_template driver_template; - -static int eata_pio_show_info(struct seq_file *m, struct Scsi_Host *shost) -{ - seq_printf(m, "EATA (Extended Attachment) PIO driver version: " - "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB); - seq_printf(m, "queued commands: %10ld\n" - "processed interrupts:%10ld\n", queue_counter, int_counter); - seq_printf(m, "\nscsi%-2d: HBA %.10s\n", - shost->host_no, SD(shost)->name); - seq_printf(m, "Firmware revision: v%s\n", - SD(shost)->revision); - seq_puts(m, "IO: PIO\n"); - seq_printf(m, "Base IO : %#.4x\n", (u32) shost->base); - seq_printf(m, "Host Bus: %s\n", - (SD(shost)->bustype == 'P')?"PCI ": - (SD(shost)->bustype == 'E')?"EISA":"ISA "); - return 0; -} - -static int eata_pio_release(struct Scsi_Host *sh) -{ - hostdata *hd = SD(sh); - if (sh->irq && reg_IRQ[sh->irq] == 1) - free_irq(sh->irq, NULL); - else - reg_IRQ[sh->irq]--; - if (SD(sh)->channel == 0) { - if (sh->io_port && sh->n_io_port) - release_region(sh->io_port, sh->n_io_port); - } - /* At this point the PCI reference can go */ - if (hd->pdev) - pci_dev_put(hd->pdev); - return 1; -} - -static void IncStat(struct scsi_pointer *SCp, unsigned int Increment) -{ - SCp->ptr += Increment; - if ((SCp->this_residual -= Increment) == 0) { - if ((--SCp->buffers_residual) == 0) - SCp->Status = 0; - else { - SCp->buffer++; - SCp->ptr = sg_virt(SCp->buffer); - SCp->this_residual = SCp->buffer->length; - } - } -} - -static irqreturn_t eata_pio_int_handler(int irq, void *dev_id); - -static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - irqreturn_t ret; - - spin_lock_irqsave(dev->host_lock, flags); - ret = eata_pio_int_handler(irq, dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return ret; -} - -static irqreturn_t eata_pio_int_handler(int irq, void *dev_id) -{ - unsigned int eata_stat = 0xfffff; - struct scsi_cmnd *cmd; - hostdata *hd; - struct eata_ccb *cp; - unsigned long base; - unsigned int x, z; - struct Scsi_Host *sh; - unsigned short zwickel = 0; - unsigned char stat, odd; - irqreturn_t ret = IRQ_NONE; - - for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) - { - if (sh->irq != irq) - continue; - if (inb(sh->base + HA_RSTATUS) & HA_SBUSY) - continue; - - int_counter++; - ret = IRQ_HANDLED; - - hd = SD(sh); - - cp = &hd->ccb[0]; - cmd = cp->cmd; - base = cmd->device->host->base; - - do { - stat = inb(base + HA_RSTATUS); - if (stat & HA_SDRQ) { - if (cp->DataIn) { - z = 256; - odd = 0; - while ((cmd->SCp.Status) && ((z > 0) || (odd))) { - if (odd) { - *(cmd->SCp.ptr) = zwickel >> 8; - IncStat(&cmd->SCp, 1); - odd = 0; - } - x = min_t(unsigned int, z, cmd->SCp.this_residual / 2); - insw(base + HA_RDATA, cmd->SCp.ptr, x); - z -= x; - IncStat(&cmd->SCp, 2 * x); - if ((z > 0) && (cmd->SCp.this_residual == 1)) { - zwickel = inw(base + HA_RDATA); - *(cmd->SCp.ptr) = zwickel & 0xff; - IncStat(&cmd->SCp, 1); - z--; - odd = 1; - } - } - while (z > 0) { - zwickel = inw(base + HA_RDATA); - z--; - } - } else { /* cp->DataOut */ - - odd = 0; - z = 256; - while ((cmd->SCp.Status) && ((z > 0) || (odd))) { - if (odd) { - zwickel += *(cmd->SCp.ptr) << 8; - IncStat(&cmd->SCp, 1); - outw(zwickel, base + HA_RDATA); - z--; - odd = 0; - } - x = min_t(unsigned int, z, cmd->SCp.this_residual / 2); - outsw(base + HA_RDATA, cmd->SCp.ptr, x); - z -= x; - IncStat(&cmd->SCp, 2 * x); - if ((z > 0) && (cmd->SCp.this_residual == 1)) { - zwickel = *(cmd->SCp.ptr); - zwickel &= 0xff; - IncStat(&cmd->SCp, 1); - odd = 1; - } - } - while (z > 0 || odd) { - outw(zwickel, base + HA_RDATA); - z--; - odd = 0; - } - } - } - } - while ((stat & HA_SDRQ) || ((stat & HA_SMORE) && hd->moresupport)); - - /* terminate handler if HBA goes busy again, i.e. transfers - * more data */ - - if (stat & HA_SBUSY) - break; - - /* OK, this is quite stupid, but I haven't found any correct - * way to get HBA&SCSI status so far */ - - if (!(inb(base + HA_RSTATUS) & HA_SERROR)) { - cmd->result = (DID_OK << 16); - hd->devflags |= (1 << cp->cp_id); - } else if (hd->devflags & (1 << cp->cp_id)) - cmd->result = (DID_OK << 16) + 0x02; - else - cmd->result = (DID_NO_CONNECT << 16); - - if (cp->status == LOCKED) { - cp->status = FREE; - eata_stat = inb(base + HA_RSTATUS); - printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n"); - return ret; - } -#if DBG_INTR2 - if (stat != 0x50) - printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, cmd->result); -#endif - - cp->status = FREE; /* now we can release the slot */ - - cmd->scsi_done(cmd); - } - - return ret; -} - -static inline unsigned int eata_pio_send_command(unsigned long base, unsigned char command) -{ - unsigned int loop = 50; - - while (inb(base + HA_RSTATUS) & HA_SBUSY) - if (--loop == 0) - return 1; - - /* Enable interrupts for HBA. It is not the best way to do it at this - * place, but I hope that it doesn't interfere with the IDE driver - * initialization this way */ - - outb(HA_CTRL_8HEADS, base + HA_CTRLREG); - - outb(command, base + HA_WCOMMAND); - return 0; -} - -static int eata_pio_queue_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - unsigned int x, y; - unsigned long base; - - hostdata *hd; - struct Scsi_Host *sh; - struct eata_ccb *cp; - - queue_counter++; - - hd = HD(cmd); - sh = cmd->device->host; - base = sh->base; - - /* use only slot 0, as 2001 can handle only one cmd at a time */ - - y = x = 0; - - if (hd->ccb[y].status != FREE) { - - DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n", sh->can_queue, x, y)); -#if DEBUG_EATA - panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld " "intrno: %ld\n", queue_counter, int_counter); -#else - panic(KERN_EMERG "eata_pio: run out of queue slots....\n"); -#endif - } - - cp = &hd->ccb[y]; - - memset(cp, 0, sizeof(struct eata_ccb)); - - cp->status = USED; /* claim free slot */ - - DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "eata_pio_queue 0x%p, y %d\n", cmd, y)); - - cmd->scsi_done = (void *) done; - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - cp->DataOut = 1; /* Output mode */ - else - cp->DataIn = 0; /* Input mode */ - - cp->Interpret = (cmd->device->id == hd->hostid); - cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd)); - cp->Auto_Req_Sen = 0; - cp->cp_reqDMA = 0; - cp->reqlen = 0; - - cp->cp_id = cmd->device->id; - cp->cp_lun = cmd->device->lun; - cp->cp_dispri = 0; - cp->cp_identify = 1; - memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); - - cp->cp_statDMA = 0; - - cp->cp_viraddr = cp; - cp->cmd = cmd; - cmd->host_scribble = (char *) &hd->ccb[y]; - - if (!scsi_bufflen(cmd)) { - cmd->SCp.buffers_residual = 1; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - cmd->SCp.buffer = NULL; - } else { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd); - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } - cmd->SCp.Status = (cmd->SCp.this_residual != 0); /* TRUE as long as bytes - * are to transfer */ - - if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) { - cmd->result = DID_BUS_BUSY << 16; - scmd_printk(KERN_NOTICE, cmd, - "eata_pio_queue pid 0x%p, HBA busy, " - "returning DID_BUS_BUSY, done.\n", cmd); - done(cmd); - cp->status = FREE; - return 0; - } - /* FIXME: timeout */ - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - cpu_relax(); - outsw(base + HA_RDATA, cp, hd->cplen); - outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND); - for (x = 0; x < hd->cppadlen; x++) - outw(0, base + HA_RDATA); - - DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "Queued base %#.4lx cmd: 0x%p " - "slot %d irq %d\n", sh->base, cmd, y, sh->irq)); - - return 0; -} - -static DEF_SCSI_QCMD(eata_pio_queue) - -static int eata_pio_abort(struct scsi_cmnd *cmd) -{ - unsigned int loop = 100; - - DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_abort called pid: 0x%p\n", cmd)); - - while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY) - if (--loop == 0) { - printk(KERN_WARNING "eata_pio: abort, timeout error.\n"); - return FAILED; - } - if (CD(cmd)->status == FREE) { - DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n")); - return FAILED; - } - if (CD(cmd)->status == USED) { - DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n")); - /* We want to sleep a bit more here */ - return FAILED; /* SNOOZE */ - } - if (CD(cmd)->status == RESET) { - printk(KERN_WARNING "eata_pio: abort, command reset error.\n"); - return FAILED; - } - if (CD(cmd)->status == LOCKED) { - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot " "locked.\n")); - return FAILED; - } - panic("eata_pio: abort: invalid slot status\n"); -} - -static int eata_pio_host_reset(struct scsi_cmnd *cmd) -{ - unsigned int x, limit = 0; - unsigned char success = 0; - struct scsi_cmnd *sp; - struct Scsi_Host *host = cmd->device->host; - - DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_reset called\n")); - - spin_lock_irq(host->host_lock); - - if (HD(cmd)->state == RESET) { - printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n"); - spin_unlock_irq(host->host_lock); - return FAILED; - } - - /* force all slots to be free */ - - for (x = 0; x < cmd->device->host->can_queue; x++) { - - if (HD(cmd)->ccb[x].status == FREE) - continue; - - sp = HD(cmd)->ccb[x].cmd; - HD(cmd)->ccb[x].status = RESET; - printk(KERN_WARNING "eata_pio_reset: slot %d in reset.\n", x); - - if (sp == NULL) - panic("eata_pio_reset: slot %d, sp==NULL.\n", x); - } - - /* hard reset the HBA */ - outb(EATA_CMD_RESET, cmd->device->host->base + HA_WCOMMAND); - - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n")); - HD(cmd)->state = RESET; - - spin_unlock_irq(host->host_lock); - msleep(3000); - spin_lock_irq(host->host_lock); - - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit)); - - for (x = 0; x < cmd->device->host->can_queue; x++) { - - /* Skip slots already set free by interrupt */ - if (HD(cmd)->ccb[x].status != RESET) - continue; - - sp = HD(cmd)->ccb[x].cmd; - sp->result = DID_RESET << 16; - - /* This mailbox is terminated */ - printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n", x); - HD(cmd)->ccb[x].status = FREE; - - sp->scsi_done(sp); - } - - HD(cmd)->state = 0; - - spin_unlock_irq(host->host_lock); - - if (success) { /* hmmm... */ - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n")); - return SUCCESS; - } else { - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n")); - return FAILED; - } -} - -static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned int id, unsigned long cplen, unsigned short cppadlen) -{ - struct eata_ccb cp; - static char buff[256]; - int z; - - memset(&cp, 0, sizeof(struct eata_ccb)); - memset(buff, 0, sizeof(buff)); - - cp.DataIn = 1; - cp.Interpret = 1; /* Interpret command */ - - cp.cp_datalen = cpu_to_be32(254); - cp.cp_dataDMA = cpu_to_be32(0); - - cp.cp_id = id; - cp.cp_lun = 0; - - cp.cp_cdb[0] = INQUIRY; - cp.cp_cdb[1] = 0; - cp.cp_cdb[2] = 0; - cp.cp_cdb[3] = 0; - cp.cp_cdb[4] = 254; - cp.cp_cdb[5] = 0; - - if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) - return NULL; - - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - cpu_relax(); - - outsw(base + HA_RDATA, &cp, cplen); - outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND); - for (z = 0; z < cppadlen; z++) - outw(0, base + HA_RDATA); - - while (inb(base + HA_RSTATUS) & HA_SBUSY) - cpu_relax(); - - if (inb(base + HA_RSTATUS) & HA_SERROR) - return NULL; - else if (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - return NULL; - else { - insw(base + HA_RDATA, &buff, 127); - while (inb(base + HA_RSTATUS) & HA_SDRQ) - inw(base + HA_RDATA); - return buff; - } -} - -static int get_pio_conf_PIO(unsigned long base, struct get_conf *buf) -{ - unsigned long loop = HZ / 2; - int z; - unsigned short *p; - - if (!request_region(base, 9, "eata_pio")) - return 0; - - memset(buf, 0, sizeof(struct get_conf)); - - while (inb(base + HA_RSTATUS) & HA_SBUSY) - if (--loop == 0) - goto fail; - - DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#lx\n", base)); - eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG); - - loop = 50; - for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) { - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - if (--loop == 0) - goto fail; - - loop = 50; - *p = inw(base + HA_RDATA); - } - if (inb(base + HA_RSTATUS) & HA_SERROR) { - DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during " - "transfer for HBA at %lx\n", base)); - goto fail; - } - - if (cpu_to_be32(EATA_SIGNATURE) != buf->signature) - goto fail; - - DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found " - "at %#4lx EATA Level: %x\n", - base, (unsigned int) (buf->version))); - - while (inb(base + HA_RSTATUS) & HA_SDRQ) - inw(base + HA_RDATA); - - if (!ALLOW_DMA_BOARDS) { - for (z = 0; z < MAXISA; z++) - if (base == ISAbases[z]) { - buf->IRQ = ISAirqs[z]; - break; - } - } - - return 1; - - fail: - release_region(base, 9); - return 0; -} - -static void print_pio_config(struct get_conf *gc) -{ - printk("Please check values: (read config data)\n"); - printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", be32_to_cpu(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support); - printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], be16_to_cpu(gc->queuesiz), be16_to_cpu(gc->SGsiz), gc->SECOND); - printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest); -} - -static unsigned int print_selftest(unsigned int base) -{ - unsigned char buffer[512]; -#ifdef VERBOSE_SETUP - int z; -#endif - - printk("eata_pio: executing controller self test & setup...\n"); - while (inb(base + HA_RSTATUS) & HA_SBUSY); - outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND); - do { - while (inb(base + HA_RSTATUS) & HA_SBUSY) - /* nothing */ ; - if (inb(base + HA_RSTATUS) & HA_SDRQ) { - insw(base + HA_RDATA, &buffer, 256); -#ifdef VERBOSE_SETUP - /* no beeps please... */ - for (z = 0; z < 511 && buffer[z]; z++) - if (buffer[z] != 7) - printk("%c", buffer[z]); -#endif - } - } while (inb(base + HA_RSTATUS) & (HA_SBUSY | HA_SDRQ)); - - return (!(inb(base + HA_RSTATUS) & HA_SERROR)); -} - -static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev) -{ - unsigned long size = 0; - char *buff; - unsigned long cplen; - unsigned short cppadlen; - struct Scsi_Host *sh; - hostdata *hd; - - DBG(DBG_REGISTER, print_pio_config(gc)); - - if (gc->DMA_support) { - printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n", base); - if (!ALLOW_DMA_BOARDS) - return 0; - } - - if ((buff = get_pio_board_data(base, gc->IRQ, gc->scsi_id[3], cplen = (cpu_to_be32(gc->cplen) + 1) / 2, cppadlen = (cpu_to_be16(gc->cppadlen) + 1) / 2)) == NULL) { - printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", base); - return 0; - } - - if (!print_selftest(base) && !ALLOW_DMA_BOARDS) { - printk("HBA at %#lx failed while performing self test & setup.\n", base); - return 0; - } - - size = sizeof(hostdata) + (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz)); - - sh = scsi_register(&driver_template, size); - if (sh == NULL) - return 0; - - if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */ - if (!request_irq(gc->IRQ, do_eata_pio_int_handler, 0, "EATA-PIO", sh)) { - reg_IRQ[gc->IRQ]++; - if (!gc->IRQ_TR) - reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */ - } else { - printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ); - return 0; - } - } else { /* More than one HBA on this IRQ */ - if (reg_IRQL[gc->IRQ]) { - printk("Can't support more than one HBA on this IRQ,\n" " if the IRQ is edge triggered. Sorry.\n"); - return 0; - } else - reg_IRQ[gc->IRQ]++; - } - - hd = SD(sh); - - memset(hd->ccb, 0, (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz))); - memset(hd->reads, 0, sizeof(hd->reads)); - - strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor)); - strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name)); - SD(sh)->revision[0] = buff[32]; - SD(sh)->revision[1] = buff[33]; - SD(sh)->revision[2] = buff[34]; - SD(sh)->revision[3] = '.'; - SD(sh)->revision[4] = buff[35]; - SD(sh)->revision[5] = 0; - - switch (be32_to_cpu(gc->len)) { - case 0x1c: - SD(sh)->EATA_revision = 'a'; - break; - case 0x1e: - SD(sh)->EATA_revision = 'b'; - break; - case 0x22: - SD(sh)->EATA_revision = 'c'; - break; - case 0x24: - SD(sh)->EATA_revision = 'z'; - break; - default: - SD(sh)->EATA_revision = '?'; - } - - if (be32_to_cpu(gc->len) >= 0x22) { - if (gc->is_PCI) - hd->bustype = IS_PCI; - else if (gc->is_EISA) - hd->bustype = IS_EISA; - else - hd->bustype = IS_ISA; - } else { - if (buff[21] == '4') - hd->bustype = IS_PCI; - else if (buff[21] == '2') - hd->bustype = IS_EISA; - else - hd->bustype = IS_ISA; - } - - SD(sh)->cplen = cplen; - SD(sh)->cppadlen = cppadlen; - SD(sh)->hostid = gc->scsi_id[3]; - SD(sh)->devflags = 1 << gc->scsi_id[3]; - SD(sh)->moresupport = gc->MORE_support; - sh->unique_id = base; - sh->base = base; - sh->io_port = base; - sh->n_io_port = 9; - sh->irq = gc->IRQ; - sh->dma_channel = PIO; - sh->this_id = gc->scsi_id[3]; - sh->can_queue = 1; - sh->cmd_per_lun = 1; - sh->sg_tablesize = SG_ALL; - - hd->channel = 0; - - hd->pdev = pci_dev_get(pdev); /* Keep a PCI reference */ - - sh->max_id = 8; - sh->max_lun = 8; - - if (gc->SECOND) - hd->primary = 0; - else - hd->primary = 1; - - hd->next = NULL; /* build a linked list of all HBAs */ - hd->prev = last_HBA; - if (hd->prev != NULL) - SD(hd->prev)->next = sh; - last_HBA = sh; - if (first_HBA == NULL) - first_HBA = sh; - registered_HBAs++; - return (1); -} - -static void find_pio_ISA(struct get_conf *buf) -{ - int i; - - for (i = 0; i < MAXISA; i++) { - if (!ISAbases[i]) - continue; - if (!get_pio_conf_PIO(ISAbases[i], buf)) - continue; - if (!register_pio_HBA(ISAbases[i], buf, NULL)) - release_region(ISAbases[i], 9); - else - ISAbases[i] = 0; - } - return; -} - -static void find_pio_EISA(struct get_conf *buf) -{ - u32 base; - int i; - -#ifdef CHECKPAL - u8 pal1, pal2, pal3; -#endif - - for (i = 0; i < MAXEISA; i++) { - if (EISAbases[i]) { /* Still a possibility ? */ - - base = 0x1c88 + (i * 0x1000); -#ifdef CHECKPAL - pal1 = inb((u16) base - 8); - pal2 = inb((u16) base - 7); - pal3 = inb((u16) base - 6); - - if (((pal1 == 0x12) && (pal2 == 0x14)) || ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) || ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) { - DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: " "%x %x %x \n", (int) pal1, (int) pal2, (int) pal3)); -#endif - if (get_pio_conf_PIO(base, buf)) { - DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf)); - if (buf->IRQ) { - if (!register_pio_HBA(base, buf, NULL)) - release_region(base, 9); - } else { - printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n"); - release_region(base, 9); - } - } - /* Nothing found here so we take it from the list */ - EISAbases[i] = 0; -#ifdef CHECKPAL - } -#endif - } - } - return; -} - -static void find_pio_PCI(struct get_conf *buf) -{ -#ifndef CONFIG_PCI - printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n"); -#else - struct pci_dev *dev = NULL; - unsigned long base, x; - - while ((dev = pci_get_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) { - DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev))); - if (pci_enable_device(dev)) - continue; - pci_set_master(dev); - base = pci_resource_flags(dev, 0); - if (base & IORESOURCE_MEM) { - printk("eata_pio: invalid base address of device %s\n", pci_name(dev)); - continue; - } - base = pci_resource_start(dev, 0); - /* EISA tag there ? */ - if ((inb(base) == 0x12) && (inb(base + 1) == 0x14)) - continue; /* Jep, it's forced, so move on */ - base += 0x10; /* Now, THIS is the real address */ - if (base != 0x1f8) { - /* We didn't find it in the primary search */ - if (get_pio_conf_PIO(base, buf)) { - if (buf->FORCADR) { /* If the address is forced */ - release_region(base, 9); - continue; /* we'll find it later */ - } - - /* OK. We made it till here, so we can go now - * and register it. We only have to check and - * eventually remove it from the EISA and ISA list - */ - - if (!register_pio_HBA(base, buf, dev)) { - release_region(base, 9); - continue; - } - - if (base < 0x1000) { - for (x = 0; x < MAXISA; ++x) { - if (ISAbases[x] == base) { - ISAbases[x] = 0; - break; - } - } - } else if ((base & 0x0fff) == 0x0c88) { - x = (base >> 12) & 0x0f; - EISAbases[x] = 0; - } - } -#ifdef CHECK_BLINK - else if (check_blink_state(base)) { - printk("eata_pio: HBA is in BLINK state.\n" "Consult your HBAs manual to correct this.\n"); - } -#endif - } - } -#endif /* #ifndef CONFIG_PCI */ -} - -static int eata_pio_detect(struct scsi_host_template *tpnt) -{ - struct Scsi_Host *HBA_ptr; - struct get_conf gc; - int i; - - find_pio_PCI(&gc); - find_pio_EISA(&gc); - find_pio_ISA(&gc); - - for (i = 0; i < MAXIRQ; i++) - if (reg_IRQ[i]) - request_irq(i, do_eata_pio_int_handler, 0, "EATA-PIO", NULL); - - HBA_ptr = first_HBA; - - if (registered_HBAs != 0) { - printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n" - "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n" " Alfred Arnold, a.arnold@kfa-juelich.de\n" "This release only supports DASD devices (harddisks)\n", VER_MAJOR, VER_MINOR, VER_SUB); - - printk("Registered HBAs:\n"); - printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n"); - for (i = 1; i <= registered_HBAs; i++) { - printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d %d %d %c" - " %2d %2d %2d\n", - HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision, - SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ? - "PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ", - HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id, - SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue, - HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun); - HBA_ptr = SD(HBA_ptr)->next; - } - } - return (registered_HBAs); -} - -static struct scsi_host_template driver_template = { - .proc_name = "eata_pio", - .name = "EATA (Extended Attachment) PIO driver", - .show_info = eata_pio_show_info, - .detect = eata_pio_detect, - .release = eata_pio_release, - .queuecommand = eata_pio_queue, - .eh_abort_handler = eata_pio_abort, - .eh_host_reset_handler = eata_pio_host_reset, - .use_clustering = ENABLE_CLUSTERING, -}; - -MODULE_AUTHOR("Michael Neuffer, Alfred Arnold"); -MODULE_DESCRIPTION("EATA SCSI PIO driver"); -MODULE_LICENSE("GPL"); - -#include "scsi_module.c" diff --git a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h deleted file mode 100644 index 5b5e3d13670b..000000000000 --- a/drivers/scsi/eata_pio.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/******************************************************** -* Header file for eata_pio.c Linux EATA-PIO SCSI driver * -* (c) 1993-96 Michael Neuffer * -********************************************************* -* last change: 2002/11/02 * -********************************************************/ - - -#ifndef _EATA_PIO_H -#define _EATA_PIO_H - -#define VER_MAJOR 0 -#define VER_MINOR 0 -#define VER_SUB "1b" - -/************************************************************************ - * Here you can switch parts of the code on and of * - ************************************************************************/ - -#define VERBOSE_SETUP /* show startup screen of 2001 */ -#define ALLOW_DMA_BOARDS 1 - -/************************************************************************ - * Debug options. * - * Enable DEBUG and whichever options you require. * - ************************************************************************/ -#define DEBUG_EATA 1 /* Enable debug code. */ -#define DPT_DEBUG 0 /* Bobs special */ -#define DBG_DELAY 0 /* Build in delays so debug messages can be - * be read before they vanish of the top of - * the screen! - */ -#define DBG_PROBE 0 /* Debug probe routines. */ -#define DBG_ISA 0 /* Trace ISA routines */ -#define DBG_EISA 0 /* Trace EISA routines */ -#define DBG_PCI 0 /* Trace PCI routines */ -#define DBG_PIO 0 /* Trace get_config_PIO */ -#define DBG_COM 0 /* Trace command call */ -#define DBG_QUEUE 0 /* Trace command queueing. */ -#define DBG_INTR 0 /* Trace interrupt service routine. */ -#define DBG_INTR2 0 /* Trace interrupt service routine. */ -#define DBG_PROC 0 /* Debug proc-fs related statistics */ -#define DBG_PROC_WRITE 0 -#define DBG_REGISTER 0 /* */ -#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort) */ - -#if DEBUG_EATA -#define DBG(x, y) if ((x)) {y;} -#else -#define DBG(x, y) -#endif - -#endif /* _EATA_PIO_H */ diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index 1da6407ee142..858c3b33db78 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -962,7 +962,6 @@ struct esas2r_adapter { * Function Declarations * SCSI functions */ -int esas2r_release(struct Scsi_Host *); const char *esas2r_info(struct Scsi_Host *); int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq, struct esas2r_sas_nvram *data); @@ -984,7 +983,6 @@ int esas2r_target_reset(struct scsi_cmnd *cmd); /* Internal functions */ int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid, int index); -int esas2r_cleanup(struct Scsi_Host *host); int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count); int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off, int count); diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 5b14dd29b764..9dffcb28c9b7 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -661,27 +661,6 @@ void esas2r_kill_adapter(int i) } } -int esas2r_cleanup(struct Scsi_Host *host) -{ - struct esas2r_adapter *a; - int index; - - if (host == NULL) { - int i; - - esas2r_debug("esas2r_cleanup everything"); - for (i = 0; i < MAX_ADAPTERS; i++) - esas2r_kill_adapter(i); - return -1; - } - - esas2r_debug("esas2r_cleanup called for host %p", host); - a = (struct esas2r_adapter *)host->hostdata; - index = a->index; - esas2r_kill_adapter(index); - return index; -} - int esas2r_suspend(struct pci_dev *pdev, pm_message_t state) { struct Scsi_Host *host = pci_get_drvdata(pdev); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 4eb14301a497..e07eac5be087 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -235,7 +235,6 @@ static struct scsi_host_template driver_template = { .module = THIS_MODULE, .show_info = esas2r_show_info, .name = ESAS2R_LONGNAME, - .release = esas2r_release, .info = esas2r_info, .ioctl = esas2r_ioctl, .queuecommand = esas2r_queuecommand, @@ -520,44 +519,16 @@ static int esas2r_probe(struct pci_dev *pcid, static void esas2r_remove(struct pci_dev *pdev) { - struct Scsi_Host *host; - int index; - - if (pdev == NULL) { - esas2r_log(ESAS2R_LOG_WARN, "esas2r_remove pdev==NULL"); - return; - } - - host = pci_get_drvdata(pdev); - - if (host == NULL) { - /* - * this can happen if pci_set_drvdata was already called - * to clear the host pointer. if this is the case, we - * are okay; this channel has already been cleaned up. - */ - - return; - } + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata; esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "esas2r_remove(%p) called; " "host:%p", pdev, host); - index = esas2r_cleanup(host); - - if (index < 0) - esas2r_log_dev(ESAS2R_LOG_WARN, &(pdev->dev), - "unknown host in %s", - __func__); - + esas2r_kill_adapter(a->index); found_adapters--; - - /* if this was the last adapter, clean up the rest of the driver */ - - if (found_adapters == 0) - esas2r_cleanup(NULL); } static int __init esas2r_init(void) @@ -638,30 +609,7 @@ static int __init esas2r_init(void) for (i = 0; i < MAX_ADAPTERS; i++) esas2r_adapters[i] = NULL; - /* initialize */ - - driver_template.module = THIS_MODULE; - - if (pci_register_driver(&esas2r_pci_driver) != 0) - esas2r_log(ESAS2R_LOG_CRIT, "pci_register_driver FAILED"); - else - esas2r_log(ESAS2R_LOG_INFO, "pci_register_driver() OK"); - - if (!found_adapters) { - pci_unregister_driver(&esas2r_pci_driver); - esas2r_cleanup(NULL); - - esas2r_log(ESAS2R_LOG_CRIT, - "driver will not be loaded because no ATTO " - "%s devices were found", - ESAS2R_DRVR_NAME); - return -1; - } else { - esas2r_log(ESAS2R_LOG_INFO, "found %d adapters", - found_adapters); - } - - return 0; + return pci_register_driver(&esas2r_pci_driver); } /* Handle ioctl calls to "/proc/scsi/esas2r/ATTOnode" */ @@ -753,18 +701,6 @@ int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh) } -int esas2r_release(struct Scsi_Host *sh) -{ - esas2r_log_dev(ESAS2R_LOG_INFO, &(sh->shost_gendev), - "esas2r_release() called"); - - esas2r_cleanup(sh); - if (sh->irq) - free_irq(sh->irq, NULL); - scsi_unregister(sh); - return 0; -} - const char *esas2r_info(struct Scsi_Host *sh) { struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata; diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c deleted file mode 100644 index ebbe5a3e665d..000000000000 --- a/drivers/scsi/fdomain.c +++ /dev/null @@ -1,1783 +0,0 @@ -/* fdomain.c -- Future Domain TMC-16x0 SCSI driver - * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Mon Dec 28 21:59:02 1998 by faith@acm.org - * Author: Rickard E. Faith, faith@cs.unc.edu - * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org) - * Shared IRQ supported added 7/7/2001 Alan Cox <alan@lxorguk.ukuu.org.uk> - - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - - ************************************************************************** - - SUMMARY: - - Future Domain BIOS versions supported for autodetect: - 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61 - Chips are supported: - TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70 - Boards supported: - Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX - Future Domain TMC-3260 (PCI) - Quantum ISA-200S, ISA-250MG - Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead] - IBM ? - LILO/INSMOD command-line options: - fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>] - - - - NOTE: - - The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it. - Use the aic7xxx driver for this board. - - The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right - driver for that card. Unfortunately, the boxes will probably just say - "2920", so you'll have to look on the card for a Future Domain logo, or a - letter after the 2920. - - - - THANKS: - - Thanks to Adaptec for providing PCI boards for testing. This finally - enabled me to test the PCI detection and correct it for PCI boards that do - not have a BIOS at a standard ISA location. For PCI boards, LILO/INSMOD - command-line options should no longer be needed. --RF 18Nov98 - - - - DESCRIPTION: - - This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680 - TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a - 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin - high-density external connector. The 1670 and 1680 have floppy disk - controllers built in. The TMC-3260 is a PCI bus card. - - Future Domain's older boards are based on the TMC-1800 chip, and this - driver was originally written for a TMC-1680 board with the TMC-1800 chip. - More recently, boards are being produced with the TMC-18C50 and TMC-18C30 - chips. The latest and greatest board may not work with this driver. If - you have to patch this driver so that it will recognize your board's BIOS - signature, then the driver may fail to function after the board is - detected. - - Please note that the drive ordering that Future Domain implemented in BIOS - versions 3.4 and 3.5 is the opposite of the order (currently) used by the - rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have - more than one drive, then the drive ordering will be the reverse of that - which you see under DOS. For example, under DOS SCSI ID 0 will be D: and - SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be - /dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent - with that provided by all the other SCSI drivers for Linux. If you want - this changed, you will probably have to patch the higher level SCSI code. - If you do so, please send me patches that are protected by #ifdefs. - - If you have a TMC-8xx or TMC-9xx board, then this is not the driver for - your board. Please refer to the Seagate driver for more information and - possible support. - - - - HISTORY: - - Linux Driver Driver - Version Version Date Support/Notes - - 0.0 3 May 1992 V2.0 BIOS; 1800 chip - 0.97 1.9 28 Jul 1992 - 0.98.6 3.1 27 Nov 1992 - 0.99 3.2 9 Dec 1992 - - 0.99.3 3.3 10 Jan 1993 V3.0 BIOS - 0.99.5 3.5 18 Feb 1993 - 0.99.10 3.6 15 May 1993 V3.2 BIOS; 18C50 chip - 0.99.11 3.17 3 Jul 1993 (now under RCS) - 0.99.12 3.18 13 Aug 1993 - 0.99.14 5.6 31 Oct 1993 (reselection code removed) - - 0.99.15 5.9 23 Jan 1994 V3.4 BIOS (preliminary) - 1.0.8/1.1.1 5.15 1 Apr 1994 V3.4 BIOS; 18C30 chip (preliminary) - 1.0.9/1.1.3 5.16 7 Apr 1994 V3.4 BIOS; 18C30 chip - 1.1.38 5.18 30 Jul 1994 36C70 chip (PCI version of 18C30) - 1.1.62 5.20 2 Nov 1994 V3.5 BIOS - 1.1.73 5.22 7 Dec 1994 Quantum ISA-200S board; V2.0 BIOS - - 1.1.82 5.26 14 Jan 1995 V3.5 BIOS; TMC-1610M/MER/MEX board - 1.2.10 5.28 5 Jun 1995 Quantum ISA-250MG board; V2.0, V2.01 BIOS - 1.3.4 5.31 23 Jun 1995 PCI BIOS-32 detection (preliminary) - 1.3.7 5.33 4 Jul 1995 PCI BIOS-32 detection - 1.3.28 5.36 17 Sep 1995 V3.61 BIOS; LILO command-line support - 1.3.34 5.39 12 Oct 1995 V3.60 BIOS; /proc - 1.3.72 5.39 8 Feb 1996 Adaptec AHA-2920 board - 1.3.85 5.41 4 Apr 1996 - 2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards - 2.1.1 5.45 2 Oct 1996 Update ROM accesses for 2.1.x - 2.1.97 5.46 23 Apr 1998 Rewritten PCI detection routines [mj] - 2.1.11x 5.47 9 Aug 1998 Touched for 8 SCSI disk majors support - 5.48 18 Nov 1998 BIOS no longer needed for PCI detection - 2.2.0 5.50 28 Dec 1998 Support insmod parameters - - - REFERENCES USED: - - "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation, - 1990. - - "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain - Corporation, January 1992. - - "LXT SCSI Products: Specifications and OEM Technical Manual (Revision - B/September 1991)", Maxtor Corporation, 1991. - - "7213S product Manual (Revision P3)", Maxtor Corporation, 1992. - - "Draft Proposed American National Standard: Small Computer System - Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109, - revision 10h, October 17, 1991) - - Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric - Youngdale (ericy@cais.com), 1992. - - Private communication, Tuong Le (Future Domain Engineering department), - 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and - TMC-18C30 detection.) - - Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page - 60 (2.39: Disk Partition Table Layout). - - "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page - 6-1. - - - - NOTES ON REFERENCES: - - The Maxtor manuals were free. Maxtor telephone technical support is - great! - - The Future Domain manuals were $25 and $35. They document the chip, not - the TMC-16x0 boards, so some information I had to guess at. In 1992, - Future Domain sold DOS BIOS source for $250 and the UN*X driver source was - $750, but these required a non-disclosure agreement, so even if I could - have afforded them, they would *not* have been useful for writing this - publicly distributable driver. Future Domain technical support has - provided some information on the phone and have sent a few useful FAXs. - They have been much more helpful since they started to recognize that the - word "Linux" refers to an operating system :-). - - - - ALPHA TESTERS: - - There are many other alpha testers that come and go as the driver - develops. The people listed here were most helpful in times of greatest - need (mostly early on -- I've probably left out a few worthy people in - more recent times): - - Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken - Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari - Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad - Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com). - - Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me - his 18C50-based card for debugging. He is the sole reason that this - driver works with the 18C50 chip. - - Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for - the version 3.4 BIOS. - - Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing - patches that support the TMC-3260, a PCI bus card with the 36C70 chip. - The 36C70 chip appears to be "completely compatible" with the 18C30 chip. - - Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the - patch for the version 3.5 BIOS. - - Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the - patch for the Quantum ISA-200S SCSI adapter. - - Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards, to - Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to some - random TMC-1680 repackaged by IBM; and to Mintak Ng (mintak@panix.com) for - the version 3.61 BIOS signature. - - Thanks for Mark Singer (elf@netcom.com) and Richard Simpson - (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective - work on the Quantum RAM layout. - - Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for - providing patches for proper PCI BIOS32-mediated detection of the TMC-3260 - card (a PCI bus card with the 36C70 chip). Please send James PCI-related - bug reports. - - Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option - patches. - - New PCI detection code written by Martin Mares <mj@atrey.karlin.mff.cuni.cz> - - Insmod parameter code based on patches from Daniel Graham - <graham@balance.uoregon.edu>. - - All of the alpha testers deserve much thanks. - - - - NOTES ON USER DEFINABLE OPTIONS: - - DEBUG: This turns on the printing of various debug information. - - ENABLE_PARITY: This turns on SCSI parity checking. With the current - driver, all attached devices must support SCSI parity. If none of your - devices support parity, then you can probably get the driver to work by - turning this option off. I have no way of testing this, however, and it - would appear that no one ever uses this option. - - FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the - 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by - the SCSI device, an interrupt will be raised. Therefore, this could be as - low as 0, or as high as 16. Note, however, that values which are too high - or too low seem to prevent any interrupts from occurring, and thereby lock - up the machine. I have found that 2 is a good number, but throughput may - be increased by changing this value to values which are close to 2. - Please let me know if you try any different values. - - RESELECTION: This is no longer an option, since I gave up trying to - implement it in version 4.x of this driver. It did not improve - performance at all and made the driver unstable (because I never found one - of the two race conditions which were introduced by the multiple - outstanding command code). The instability seems a very high price to pay - just so that you don't have to wait for the tape to rewind. If you want - this feature implemented, send me patches. I'll be happy to send a copy - of my (broken) driver to anyone who would like to see a copy. - - **************************************************************************/ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/proc_fs.h> -#include <linux/pci.h> -#include <linux/stat.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <scsi/scsicam.h> - - -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_ioctl.h> -#include "fdomain.h" - -#ifndef PCMCIA -MODULE_AUTHOR("Rickard E. Faith"); -MODULE_DESCRIPTION("Future domain SCSI driver"); -MODULE_LICENSE("GPL"); -#endif - - -#define VERSION "$Revision: 5.51 $" - -/* START OF USER DEFINABLE OPTIONS */ - -#define DEBUG 0 /* Enable debugging output */ -#define ENABLE_PARITY 1 /* Enable SCSI Parity */ -#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ - -/* END OF USER DEFINABLE OPTIONS */ - -#if DEBUG -#define EVERY_ACCESS 0 /* Write a line on every scsi access */ -#define ERRORS_ONLY 1 /* Only write a line if there is an error */ -#define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */ -#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */ -#define DEBUG_ABORT 1 /* Debug abort() routine */ -#define DEBUG_RESET 1 /* Debug reset() routine */ -#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */ -#else -#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ -#define ERRORS_ONLY 0 -#define DEBUG_DETECT 0 -#define DEBUG_MESSAGES 0 -#define DEBUG_ABORT 0 -#define DEBUG_RESET 0 -#define DEBUG_RACE 0 -#endif - -/* Errors are reported on the line, so we don't need to report them again */ -#if EVERY_ACCESS -#undef ERRORS_ONLY -#define ERRORS_ONLY 0 -#endif - -#if ENABLE_PARITY -#define PARITY_MASK 0x08 -#else -#define PARITY_MASK 0x00 -#endif - -enum chip_type { - unknown = 0x00, - tmc1800 = 0x01, - tmc18c50 = 0x02, - tmc18c30 = 0x03, -}; - -enum { - in_arbitration = 0x02, - in_selection = 0x04, - in_other = 0x08, - disconnect = 0x10, - aborted = 0x20, - sent_ident = 0x40, -}; - -enum in_port_type { - Read_SCSI_Data = 0, - SCSI_Status = 1, - TMC_Status = 2, - FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ - Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ - LSB_ID_Code = 5, - MSB_ID_Code = 6, - Read_Loopback = 7, - SCSI_Data_NoACK = 8, - Interrupt_Status = 9, - Configuration1 = 10, - Configuration2 = 11, /* tmc18c50/tmc18c30 only */ - Read_FIFO = 12, - FIFO_Data_Count = 14 -}; - -enum out_port_type { - Write_SCSI_Data = 0, - SCSI_Cntl = 1, - Interrupt_Cntl = 2, - SCSI_Mode_Cntl = 3, - TMC_Cntl = 4, - Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ - Write_Loopback = 7, - IO_Control = 11, /* tmc18c30 only */ - Write_FIFO = 12 -}; - -/* .bss will zero all the static variables below */ -static int port_base; -static unsigned long bios_base; -static void __iomem * bios_mem; -static int bios_major; -static int bios_minor; -static int PCI_bus; -#ifdef CONFIG_PCI -static struct pci_dev *PCI_dev; -#endif -static int Quantum; /* Quantum board variant */ -static int interrupt_level; -static volatile int in_command; -static struct scsi_cmnd *current_SC; -static enum chip_type chip = unknown; -static int adapter_mask; -static int this_id; -static int setup_called; - -#if DEBUG_RACE -static volatile int in_interrupt_flag; -#endif - -static int FIFO_Size = 0x2000; /* 8k FIFO for - pre-tmc18c30 chips */ - -static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id ); -/* Allow insmod parameters to be like LILO parameters. For example: - insmod fdomain fdomain=0x140,11 */ -static char * fdomain = NULL; -module_param(fdomain, charp, 0); - -#ifndef PCMCIA - -static unsigned long addresses[] = { - 0xc8000, - 0xca000, - 0xce000, - 0xde000, - 0xcc000, /* Extra addresses for PCI boards */ - 0xd0000, - 0xe0000, -}; -#define ADDRESS_COUNT ARRAY_SIZE(addresses) - -static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; -#define PORT_COUNT ARRAY_SIZE(ports) - -static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; - -#endif /* !PCMCIA */ - -/* - - READ THIS BEFORE YOU ADD A SIGNATURE! - - READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! - - READ EVERY WORD, ESPECIALLY THE WORD *NOT* - - This driver works *ONLY* for Future Domain cards using the TMC-1800, - TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670, - and 1680. These are all 16-bit cards. - - The following BIOS signature signatures are for boards which do *NOT* - work with this driver (these TMC-8xx and TMC-9xx boards may work with the - Seagate driver): - - FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 - FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 - FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 - FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 - FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 - FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 - FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92 - - (The cards which do *NOT* work are all 8-bit cards -- although some of - them have a 16-bit form-factor, the upper 8-bits are used only for IRQs - and are *NOT* used for data. You can tell the difference by following - the tracings on the circuit board -- if only the IRQ lines are involved, - you have a "8-bit" card, and should *NOT* use this driver.) - -*/ - -#ifndef PCMCIA - -static struct signature { - const char *signature; - int sig_offset; - int sig_length; - int major_bios_version; - int minor_bios_version; - int flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */ -} signatures[] = { - /* 1 2 3 4 5 6 */ - /* 123456789012345678901234567890123456789012345678901234567890 */ - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0, 0 }, - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0, 0 }, - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 2, 0, 2 }, - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 2, 0, 3 }, - { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 2, 0, 4 }, - { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0, 0 }, - { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2, 0 }, - { "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 3, -1, 0 }, - { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4, 0 }, - { "Future Domain Corp. V1.0008/18/93", 26, 33, 3, 4, 1 }, - { "Adaptec AHA-2920 PCI-SCSI Card", 42, 31, 3, -1, 1 }, - { "IBM F1 P264/32", 5, 14, 3, -1, 1 }, - /* This next signature may not be a 3.5 bios */ - { "Future Domain Corp. V2.0108/18/93", 5, 33, 3, 5, 0 }, - { "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 3, 5, 0 }, - { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 3, 5, 0 }, - { "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 3, 6, 0 }, - { "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 3, 6, 0 }, - { "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1, 0 }, - - /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE - Also, fix the disk geometry code for your signature and send your - changes for faith@cs.unc.edu. Above all, do *NOT* change any old - signatures! - - Note that the last line will match a "generic" 18XX bios. Because - Future Domain has changed the host SCSI ID and/or the location of the - geometry information in the on-board RAM area for each of the first - three BIOS's, it is still important to enter a fully qualified - signature in the table for any new BIOS's (after the host SCSI ID and - geometry location are verified). */ -}; - -#define SIGNATURE_COUNT ARRAY_SIZE(signatures) - -#endif /* !PCMCIA */ - -static void print_banner( struct Scsi_Host *shpnt ) -{ - if (!shpnt) return; /* This won't ever happen */ - - if (bios_major < 0 && bios_minor < 0) { - printk(KERN_INFO "scsi%d: <fdomain> No BIOS; using scsi id %d\n", - shpnt->host_no, shpnt->this_id); - } else { - printk(KERN_INFO "scsi%d: <fdomain> BIOS version ", shpnt->host_no); - - if (bios_major >= 0) printk("%d.", bios_major); - else printk("?."); - - if (bios_minor >= 0) printk("%d", bios_minor); - else printk("?."); - - printk( " at 0x%lx using scsi id %d\n", - bios_base, shpnt->this_id ); - } - - /* If this driver works for later FD PCI - boards, we will have to modify banner - for additional PCI cards, but for now if - it's PCI it's a TMC-3260 - JTM */ - printk(KERN_INFO "scsi%d: <fdomain> %s chip at 0x%x irq ", - shpnt->host_no, - chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")), - port_base); - - if (interrupt_level) - printk("%d", interrupt_level); - else - printk("<none>"); - - printk( "\n" ); -} - -int fdomain_setup(char *str) -{ - int ints[4]; - - (void)get_options(str, ARRAY_SIZE(ints), ints); - - if (setup_called++ || ints[0] < 2 || ints[0] > 3) { - printk(KERN_INFO "scsi: <fdomain> Usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n"); - printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n"); - return 0; - } - - port_base = ints[0] >= 1 ? ints[1] : 0; - interrupt_level = ints[0] >= 2 ? ints[2] : 0; - this_id = ints[0] >= 3 ? ints[3] : 0; - - bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */ - ++setup_called; - return 1; -} - -__setup("fdomain=", fdomain_setup); - - -static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ -{ - mdelay(10*amount); -} - -static inline void fdomain_make_bus_idle( void ) -{ - outb(0, port_base + SCSI_Cntl); - outb(0, port_base + SCSI_Mode_Cntl); - if (chip == tmc18c50 || chip == tmc18c30) - outb(0x21 | PARITY_MASK, port_base + TMC_Cntl); /* Clear forced intr. */ - else - outb(0x01 | PARITY_MASK, port_base + TMC_Cntl); -} - -static int fdomain_is_valid_port( int port ) -{ -#if DEBUG_DETECT - printk( " (%x%x),", - inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) ); -#endif - - /* The MCA ID is a unique id for each MCA compatible board. We - are using ISA boards, but Future Domain provides the MCA ID - anyway. We can use this ID to ensure that this is a Future - Domain TMC-1660/TMC-1680. - */ - - if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */ - if (inb( port + LSB_ID_Code ) != 0x27) return 0; - if (inb( port + MSB_ID_Code ) != 0x61) return 0; - chip = tmc1800; - } else { /* test for 0xe960 id */ - if (inb( port + MSB_ID_Code ) != 0x60) return 0; - chip = tmc18c50; - - /* Try to toggle 32-bit mode. This only - works on an 18c30 chip. (User reports - say this works, so we should switch to - it in the near future.) */ - - outb( 0x80, port + IO_Control ); - if ((inb( port + Configuration2 ) & 0x80) == 0x80) { - outb( 0x00, port + IO_Control ); - if ((inb( port + Configuration2 ) & 0x80) == 0x00) { - chip = tmc18c30; - FIFO_Size = 0x800; /* 2k FIFO */ - } - } - /* If that failed, we are an 18c50. */ - } - - return 1; -} - -static int fdomain_test_loopback( void ) -{ - int i; - int result; - - for (i = 0; i < 255; i++) { - outb( i, port_base + Write_Loopback ); - result = inb( port_base + Read_Loopback ); - if (i != result) - return 1; - } - return 0; -} - -#ifndef PCMCIA - -/* fdomain_get_irq assumes that we have a valid MCA ID for a - TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the - bios_base matches these ports. If someone was unlucky enough to have - purchased more than one Future Domain board, then they will have to - modify this code, as we only detect one board here. [The one with the - lowest bios_base.] - - Note that this routine is only used for systems without a PCI BIOS32 - (e.g., ISA bus). For PCI bus systems, this routine will likely fail - unless one of the IRQs listed in the ints array is used by the board. - Sometimes it is possible to use the computer's BIOS setup screen to - configure a PCI system so that one of these IRQs will be used by the - Future Domain card. */ - -static int fdomain_get_irq( int base ) -{ - int options = inb(base + Configuration1); - -#if DEBUG_DETECT - printk("scsi: <fdomain> Options = %x\n", options); -#endif - - /* Check for board with lowest bios_base -- - this isn't valid for the 18c30 or for - boards on the PCI bus, so just assume we - have the right board. */ - - if (chip != tmc18c30 && !PCI_bus && addresses[(options & 0xc0) >> 6 ] != bios_base) - return 0; - return ints[(options & 0x0e) >> 1]; -} - -static int fdomain_isa_detect( int *irq, int *iobase ) -{ - int i, j; - int base = 0xdeadbeef; - int flag = 0; - -#if DEBUG_DETECT - printk( "scsi: <fdomain> fdomain_isa_detect:" ); -#endif - - for (i = 0; i < ADDRESS_COUNT; i++) { - void __iomem *p = ioremap(addresses[i], 0x2000); - if (!p) - continue; -#if DEBUG_DETECT - printk( " %lx(%lx),", addresses[i], bios_base ); -#endif - for (j = 0; j < SIGNATURE_COUNT; j++) { - if (check_signature(p + signatures[j].sig_offset, - signatures[j].signature, - signatures[j].sig_length )) { - bios_major = signatures[j].major_bios_version; - bios_minor = signatures[j].minor_bios_version; - PCI_bus = (signatures[j].flag == 1); - Quantum = (signatures[j].flag > 1) ? signatures[j].flag : 0; - bios_base = addresses[i]; - bios_mem = p; - goto found; - } - } - iounmap(p); - } - -found: - if (bios_major == 2) { - /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. - Assuming the ROM is enabled (otherwise we wouldn't have been - able to read the ROM signature :-), then the ROM sets up the - RAM area with some magic numbers, such as a list of port - base addresses and a list of the disk "geometry" reported to - DOS (this geometry has nothing to do with physical geometry). - */ - - switch (Quantum) { - case 2: /* ISA_200S */ - case 3: /* ISA_250MG */ - base = readb(bios_mem + 0x1fa2) + (readb(bios_mem + 0x1fa3) << 8); - break; - case 4: /* ISA_200S (another one) */ - base = readb(bios_mem + 0x1fa3) + (readb(bios_mem + 0x1fa4) << 8); - break; - default: - base = readb(bios_mem + 0x1fcc) + (readb(bios_mem + 0x1fcd) << 8); - break; - } - -#if DEBUG_DETECT - printk( " %x,", base ); -#endif - - for (i = 0; i < PORT_COUNT; i++) { - if (base == ports[i]) { - if (!request_region(base, 0x10, "fdomain")) - break; - if (!fdomain_is_valid_port(base)) { - release_region(base, 0x10); - break; - } - *irq = fdomain_get_irq( base ); - *iobase = base; - return 1; - } - } - - /* This is a bad sign. It usually means that someone patched the - BIOS signature list (the signatures variable) to contain a BIOS - signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */ - -#if DEBUG_DETECT - printk( " RAM FAILED, " ); -#endif - } - - /* Anyway, the alternative to finding the address in the RAM is to just - search through every possible port address for one that is attached - to the Future Domain card. Don't panic, though, about reading all - these random port addresses -- there are rumors that the Future - Domain BIOS does something very similar. - - Do not, however, check ports which the kernel knows are being used by - another driver. */ - - for (i = 0; i < PORT_COUNT; i++) { - base = ports[i]; - if (!request_region(base, 0x10, "fdomain")) { -#if DEBUG_DETECT - printk( " (%x inuse),", base ); -#endif - continue; - } -#if DEBUG_DETECT - printk( " %x,", base ); -#endif - flag = fdomain_is_valid_port(base); - if (flag) - break; - release_region(base, 0x10); - } - -#if DEBUG_DETECT - if (flag) printk( " SUCCESS\n" ); - else printk( " FAILURE\n" ); -#endif - - if (!flag) return 0; /* iobase not found */ - - *irq = fdomain_get_irq( base ); - *iobase = base; - - return 1; /* success */ -} - -#else /* PCMCIA */ - -static int fdomain_isa_detect( int *irq, int *iobase ) -{ - if (irq) - *irq = 0; - if (iobase) - *iobase = 0; - return 0; -} - -#endif /* !PCMCIA */ - - -/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int* - iobase) This function gets the Interrupt Level and I/O base address from - the PCI configuration registers. */ - -#ifdef CONFIG_PCI -static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_pdev ) -{ - unsigned int pci_irq; /* PCI interrupt line */ - unsigned long pci_base; /* PCI I/O base address */ - struct pci_dev *pdev = NULL; - -#if DEBUG_DETECT - /* Tell how to print a list of the known PCI devices from bios32 and - list vendor and device IDs being used if in debug mode. */ - - printk( "scsi: <fdomain> INFO: use lspci -v to see list of PCI devices\n" ); - printk( "scsi: <fdomain> TMC-3260 detect:" - " Using Vendor ID: 0x%x and Device ID: 0x%x\n", - PCI_VENDOR_ID_FD, - PCI_DEVICE_ID_FD_36C70 ); -#endif - - if ((pdev = pci_get_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL) - return 0; - if (pci_enable_device(pdev)) - goto fail; - -#if DEBUG_DETECT - printk( "scsi: <fdomain> TMC-3260 detect:" - " PCI bus %u, device %u, function %u\n", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); -#endif - - /* We now have the appropriate device function for the FD board so we - just read the PCI config info from the registers. */ - - pci_base = pci_resource_start(pdev, 0); - pci_irq = pdev->irq; - - if (!request_region( pci_base, 0x10, "fdomain" )) - goto fail; - - /* Now we have the I/O base address and interrupt from the PCI - configuration registers. */ - - *irq = pci_irq; - *iobase = pci_base; - *ret_pdev = pdev; - -#if DEBUG_DETECT - printk( "scsi: <fdomain> TMC-3260 detect:" - " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base ); -#endif - - if (!fdomain_is_valid_port(pci_base)) { - printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" ); - release_region(pci_base, 0x10); - goto fail; - } - - /* Fill in a few global variables. Ugh. */ - bios_major = bios_minor = -1; - PCI_bus = 1; - PCI_dev = pdev; - Quantum = 0; - bios_base = 0; - - return 1; -fail: - pci_dev_put(pdev); - return 0; -} - -#endif - -struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ) -{ - int retcode; - struct Scsi_Host *shpnt; - struct pci_dev *pdev = NULL; - - if (setup_called) { -#if DEBUG_DETECT - printk( "scsi: <fdomain> No BIOS, using port_base = 0x%x, irq = %d\n", - port_base, interrupt_level ); -#endif - if (!request_region(port_base, 0x10, "fdomain")) { - printk( "scsi: <fdomain> port 0x%x is busy\n", port_base ); - printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" ); - return NULL; - } - if (!fdomain_is_valid_port( port_base )) { - printk( "scsi: <fdomain> Cannot locate chip at port base 0x%x\n", - port_base ); - printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" ); - release_region(port_base, 0x10); - return NULL; - } - } else { - int flag = 0; - -#ifdef CONFIG_PCI - /* Try PCI detection first */ - flag = fdomain_pci_bios_detect( &interrupt_level, &port_base, &pdev ); -#endif - if (!flag) { - /* Then try ISA bus detection */ - flag = fdomain_isa_detect( &interrupt_level, &port_base ); - - if (!flag) { - printk( "scsi: <fdomain> Detection failed (no card)\n" ); - return NULL; - } - } - } - - fdomain_16x0_host_reset(NULL); - - if (fdomain_test_loopback()) { - printk(KERN_ERR "scsi: <fdomain> Detection failed (loopback test failed at port base 0x%x)\n", port_base); - if (setup_called) { - printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n"); - } - goto fail; - } - - if (this_id) { - tpnt->this_id = (this_id & 0x07); - adapter_mask = (1 << tpnt->this_id); - } else { - if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) { - tpnt->this_id = 7; - adapter_mask = 0x80; - } else { - tpnt->this_id = 6; - adapter_mask = 0x40; - } - } - -/* Print out a banner here in case we can't - get resources. */ - - shpnt = scsi_register( tpnt, 0 ); - if(shpnt == NULL) { - release_region(port_base, 0x10); - return NULL; - } - shpnt->irq = interrupt_level; - shpnt->io_port = port_base; - shpnt->n_io_port = 0x10; - print_banner( shpnt ); - - /* Log IRQ with kernel */ - if (!interrupt_level) { - printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" ); - goto fail; - } else { - /* Register the IRQ with the kernel */ - - retcode = request_irq( interrupt_level, - do_fdomain_16x0_intr, pdev?IRQF_SHARED:0, "fdomain", shpnt); - - if (retcode < 0) { - if (retcode == -EINVAL) { - printk(KERN_ERR "scsi: <fdomain> IRQ %d is bad!\n", interrupt_level ); - printk(KERN_ERR " This shouldn't happen!\n" ); - printk(KERN_ERR " Send mail to faith@acm.org\n" ); - } else if (retcode == -EBUSY) { - printk(KERN_ERR "scsi: <fdomain> IRQ %d is already in use!\n", interrupt_level ); - printk(KERN_ERR " Please use another IRQ!\n" ); - } else { - printk(KERN_ERR "scsi: <fdomain> Error getting IRQ %d\n", interrupt_level ); - printk(KERN_ERR " This shouldn't happen!\n" ); - printk(KERN_ERR " Send mail to faith@acm.org\n" ); - } - printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" ); - goto fail; - } - } - return shpnt; -fail: - pci_dev_put(pdev); - release_region(port_base, 0x10); - return NULL; -} - -static int fdomain_16x0_detect(struct scsi_host_template *tpnt) -{ - if (fdomain) - fdomain_setup(fdomain); - return (__fdomain_16x0_detect(tpnt) != NULL); -} - -static const char *fdomain_16x0_info( struct Scsi_Host *ignore ) -{ - static char buffer[128]; - char *pt; - - strcpy( buffer, "Future Domain 16-bit SCSI Driver Version" ); - if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */ - strcat( buffer, strchr( VERSION, ':' ) + 1 ); - pt = strrchr( buffer, '$') - 1; - if (!pt) /* Stripped RCS Revision string? */ - pt = buffer + strlen( buffer ) - 1; - if (*pt != ' ') - ++pt; - *pt = '\0'; - } else { /* Assume VERSION is a number */ - strcat( buffer, " " VERSION ); - } - - return buffer; -} - -#if 0 -static int fdomain_arbitrate( void ) -{ - int status = 0; - unsigned long timeout; - -#if EVERY_ACCESS - printk( "fdomain_arbitrate()\n" ); -#endif - - outb(0x00, port_base + SCSI_Cntl); /* Disable data drivers */ - outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */ - outb(0x04 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */ - - timeout = 500; - do { - status = inb(port_base + TMC_Status); /* Read adapter status */ - if (status & 0x02) /* Arbitration complete */ - return 0; - mdelay(1); /* Wait one millisecond */ - } while (--timeout); - - /* Make bus idle */ - fdomain_make_bus_idle(); - -#if EVERY_ACCESS - printk( "Arbitration failed, status = %x\n", status ); -#endif -#if ERRORS_ONLY - printk( "scsi: <fdomain> Arbitration failed, status = %x\n", status ); -#endif - return 1; -} -#endif - -static int fdomain_select( int target ) -{ - int status; - unsigned long timeout; -#if ERRORS_ONLY - static int flag = 0; -#endif - - outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */ - outb(adapter_mask | (1 << target), port_base + SCSI_Data_NoACK); - - /* Stop arbitration and enable parity */ - outb(PARITY_MASK, port_base + TMC_Cntl); - - timeout = 350; /* 350 msec */ - - do { - status = inb(port_base + SCSI_Status); /* Read adapter status */ - if (status & 1) { /* Busy asserted */ - /* Enable SCSI Bus (on error, should make bus idle with 0) */ - outb(0x80, port_base + SCSI_Cntl); - return 0; - } - mdelay(1); /* wait one msec */ - } while (--timeout); - /* Make bus idle */ - fdomain_make_bus_idle(); -#if EVERY_ACCESS - if (!target) printk( "Selection failed\n" ); -#endif -#if ERRORS_ONLY - if (!target) { - if (!flag) /* Skip first failure for all chips. */ - ++flag; - else - printk( "scsi: <fdomain> Selection failed\n" ); - } -#endif - return 1; -} - -static void my_done(int error) -{ - if (in_command) { - in_command = 0; - outb(0x00, port_base + Interrupt_Cntl); - fdomain_make_bus_idle(); - current_SC->result = error; - if (current_SC->scsi_done) - current_SC->scsi_done( current_SC ); - else panic( "scsi: <fdomain> current_SC->scsi_done() == NULL" ); - } else { - panic( "scsi: <fdomain> my_done() called outside of command\n" ); - } -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif -} - -static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id) -{ - unsigned long flags; - int status; - int done = 0; - unsigned data_count; - - /* The fdomain_16x0_intr is only called via - the interrupt handler. The goal of the - sti() here is to allow other - interruptions while this routine is - running. */ - - /* Check for other IRQ sources */ - if ((inb(port_base + TMC_Status) & 0x01) == 0) - return IRQ_NONE; - - /* It is our IRQ */ - outb(0x00, port_base + Interrupt_Cntl); - - /* We usually have one spurious interrupt after each command. Ignore it. */ - if (!in_command || !current_SC) { /* Spurious interrupt */ -#if EVERY_ACCESS - printk( "Spurious interrupt, in_command = %d, current_SC = %x\n", - in_command, current_SC ); -#endif - return IRQ_NONE; - } - - /* Abort calls my_done, so we do nothing here. */ - if (current_SC->SCp.phase & aborted) { -#if DEBUG_ABORT - printk( "scsi: <fdomain> Interrupt after abort, ignoring\n" ); -#endif - /* - return IRQ_HANDLED; */ - } - -#if DEBUG_RACE - ++in_interrupt_flag; -#endif - - if (current_SC->SCp.phase & in_arbitration) { - status = inb(port_base + TMC_Status); /* Read adapter status */ - if (!(status & 0x02)) { -#if EVERY_ACCESS - printk( " AFAIL " ); -#endif - spin_lock_irqsave(current_SC->device->host->host_lock, flags); - my_done( DID_BUS_BUSY << 16 ); - spin_unlock_irqrestore(current_SC->device->host->host_lock, flags); - return IRQ_HANDLED; - } - current_SC->SCp.phase = in_selection; - - outb(0x40 | FIFO_COUNT, port_base + Interrupt_Cntl); - - outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */ - outb(adapter_mask | (1 << scmd_id(current_SC)), port_base + SCSI_Data_NoACK); - - /* Stop arbitration and enable parity */ - outb(0x10 | PARITY_MASK, port_base + TMC_Cntl); -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; - } else if (current_SC->SCp.phase & in_selection) { - status = inb(port_base + SCSI_Status); - if (!(status & 0x01)) { - /* Try again, for slow devices */ - if (fdomain_select( scmd_id(current_SC) )) { -#if EVERY_ACCESS - printk( " SFAIL " ); -#endif - spin_lock_irqsave(current_SC->device->host->host_lock, flags); - my_done( DID_NO_CONNECT << 16 ); - spin_unlock_irqrestore(current_SC->device->host->host_lock, flags); - return IRQ_HANDLED; - } else { -#if EVERY_ACCESS - printk( " AltSel " ); -#endif - /* Stop arbitration and enable parity */ - outb(0x10 | PARITY_MASK, port_base + TMC_Cntl); - } - } - current_SC->SCp.phase = in_other; - outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl); - outb(0x80, port_base + SCSI_Cntl); -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; - } - - /* current_SC->SCp.phase == in_other: this is the body of the routine */ - - status = inb(port_base + SCSI_Status); - - if (status & 0x10) { /* REQ */ - - switch (status & 0x0e) { - - case 0x08: /* COMMAND OUT */ - outb(current_SC->cmnd[current_SC->SCp.sent_command++], - port_base + Write_SCSI_Data); -#if EVERY_ACCESS - printk( "CMD = %x,", - current_SC->cmnd[ current_SC->SCp.sent_command - 1] ); -#endif - break; - case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ - if (chip != tmc1800 && !current_SC->SCp.have_data_in) { - current_SC->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl); - } - break; - case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ - if (chip != tmc1800 && !current_SC->SCp.have_data_in) { - current_SC->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, port_base + TMC_Cntl); - } - break; - case 0x0c: /* STATUS IN */ - current_SC->SCp.Status = inb(port_base + Read_SCSI_Data); -#if EVERY_ACCESS - printk( "Status = %x, ", current_SC->SCp.Status ); -#endif -#if ERRORS_ONLY - if (current_SC->SCp.Status - && current_SC->SCp.Status != 2 - && current_SC->SCp.Status != 8) { - printk( "scsi: <fdomain> target = %d, command = %x, status = %x\n", - current_SC->device->id, - current_SC->cmnd[0], - current_SC->SCp.Status ); - } -#endif - break; - case 0x0a: /* MESSAGE OUT */ - outb(MESSAGE_REJECT, port_base + Write_SCSI_Data); /* Reject */ - break; - case 0x0e: /* MESSAGE IN */ - current_SC->SCp.Message = inb(port_base + Read_SCSI_Data); -#if EVERY_ACCESS - printk( "Message = %x, ", current_SC->SCp.Message ); -#endif - if (!current_SC->SCp.Message) ++done; -#if DEBUG_MESSAGES || EVERY_ACCESS - if (current_SC->SCp.Message) { - printk( "scsi: <fdomain> message = %x\n", - current_SC->SCp.Message ); - } -#endif - break; - } - } - - if (chip == tmc1800 && !current_SC->SCp.have_data_in - && (current_SC->SCp.sent_command >= current_SC->cmd_len)) { - - if(current_SC->sc_data_direction == DMA_TO_DEVICE) - { - current_SC->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl); - } - else - { - current_SC->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, port_base + TMC_Cntl); - } - } - - if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ - while ((data_count = FIFO_Size - inw(port_base + FIFO_Data_Count)) > 512) { -#if EVERY_ACCESS - printk( "DC=%d, ", data_count ) ; -#endif - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; - if (data_count > 0) { -#if EVERY_ACCESS - printk( "%d OUT, ", data_count ); -#endif - if (data_count == 1) { - outb(*current_SC->SCp.ptr++, port_base + Write_FIFO); - --current_SC->SCp.this_residual; - } else { - data_count >>= 1; - outsw(port_base + Write_FIFO, current_SC->SCp.ptr, data_count); - current_SC->SCp.ptr += 2 * data_count; - current_SC->SCp.this_residual -= 2 * data_count; - } - } - if (!current_SC->SCp.this_residual) { - if (current_SC->SCp.buffers_residual) { - --current_SC->SCp.buffers_residual; - ++current_SC->SCp.buffer; - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - } else - break; - } - } - } - - if (current_SC->SCp.have_data_in == 1) { /* DATA IN */ - while ((data_count = inw(port_base + FIFO_Data_Count)) > 0) { -#if EVERY_ACCESS - printk( "DC=%d, ", data_count ); -#endif - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; - if (data_count) { -#if EVERY_ACCESS - printk( "%d IN, ", data_count ); -#endif - if (data_count == 1) { - *current_SC->SCp.ptr++ = inb(port_base + Read_FIFO); - --current_SC->SCp.this_residual; - } else { - data_count >>= 1; /* Number of words */ - insw(port_base + Read_FIFO, current_SC->SCp.ptr, data_count); - current_SC->SCp.ptr += 2 * data_count; - current_SC->SCp.this_residual -= 2 * data_count; - } - } - if (!current_SC->SCp.this_residual - && current_SC->SCp.buffers_residual) { - --current_SC->SCp.buffers_residual; - ++current_SC->SCp.buffer; - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - } - } - } - - if (done) { -#if EVERY_ACCESS - printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in ); -#endif - -#if ERRORS_ONLY - if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) { - char *buf = scsi_sglist(current_SC); - if ((unsigned char)(*(buf + 2)) & 0x0f) { - unsigned char key; - unsigned char code; - unsigned char qualifier; - - key = (unsigned char)(*(buf + 2)) & 0x0f; - code = (unsigned char)(*(buf + 12)); - qualifier = (unsigned char)(*(buf + 13)); - - if (key != UNIT_ATTENTION - && !(key == NOT_READY - && code == 0x04 - && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) - && !(key == ILLEGAL_REQUEST && (code == 0x25 - || code == 0x24 - || !code))) - - printk( "scsi: <fdomain> REQUEST SENSE" - " Key = %x, Code = %x, Qualifier = %x\n", - key, code, qualifier ); - } - } -#endif -#if EVERY_ACCESS - printk( "BEFORE MY_DONE. . ." ); -#endif - spin_lock_irqsave(current_SC->device->host->host_lock, flags); - my_done( (current_SC->SCp.Status & 0xff) - | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) ); - spin_unlock_irqrestore(current_SC->device->host->host_lock, flags); -#if EVERY_ACCESS - printk( "RETURNING.\n" ); -#endif - - } else { - if (current_SC->SCp.phase & disconnect) { - outb(0xd0 | FIFO_COUNT, port_base + Interrupt_Cntl); - outb(0x00, port_base + SCSI_Cntl); - } else { - outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl); - } - } -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; -} - -static int fdomain_16x0_queue_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - if (in_command) { - panic( "scsi: <fdomain> fdomain_16x0_queue() NOT REENTRANT!\n" ); - } -#if EVERY_ACCESS - printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", - SCpnt->target, - *(unsigned char *)SCpnt->cmnd, - scsi_sg_count(SCpnt), - scsi_bufflen(SCpnt)); -#endif - - fdomain_make_bus_idle(); - - current_SC = SCpnt; /* Save this for the done function */ - current_SC->scsi_done = done; - - /* Initialize static data */ - - if (scsi_sg_count(current_SC)) { - current_SC->SCp.buffer = scsi_sglist(current_SC); - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; - } else { - current_SC->SCp.ptr = NULL; - current_SC->SCp.this_residual = 0; - current_SC->SCp.buffer = NULL; - current_SC->SCp.buffers_residual = 0; - } - - current_SC->SCp.Status = 0; - current_SC->SCp.Message = 0; - current_SC->SCp.have_data_in = 0; - current_SC->SCp.sent_command = 0; - current_SC->SCp.phase = in_arbitration; - - /* Start arbitration */ - outb(0x00, port_base + Interrupt_Cntl); - outb(0x00, port_base + SCSI_Cntl); /* Disable data drivers */ - outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */ - ++in_command; - outb(0x20, port_base + Interrupt_Cntl); - outb(0x14 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */ - - return 0; -} - -static DEF_SCSI_QCMD(fdomain_16x0_queue) - -#if DEBUG_ABORT -static void print_info(struct scsi_cmnd *SCpnt) -{ - unsigned int imr; - unsigned int irr; - unsigned int isr; - - if (!SCpnt || !SCpnt->device || !SCpnt->device->host) { - printk(KERN_WARNING "scsi: <fdomain> Cannot provide detailed information\n"); - return; - } - - printk(KERN_INFO "%s\n", fdomain_16x0_info( SCpnt->device->host ) ); - print_banner(SCpnt->device->host); - switch (SCpnt->SCp.phase) { - case in_arbitration: printk("arbitration"); break; - case in_selection: printk("selection"); break; - case in_other: printk("other"); break; - default: printk("unknown"); break; - } - - printk( " (%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", - SCpnt->SCp.phase, - SCpnt->device->id, - *(unsigned char *)SCpnt->cmnd, - scsi_sg_count(SCpnt), - scsi_bufflen(SCpnt)); - printk( "sent_command = %d, have_data_in = %d, timeout = %d\n", - SCpnt->SCp.sent_command, - SCpnt->SCp.have_data_in, - SCpnt->timeout ); -#if DEBUG_RACE - printk( "in_interrupt_flag = %d\n", in_interrupt_flag ); -#endif - - imr = (inb( 0x0a1 ) << 8) + inb( 0x21 ); - outb( 0x0a, 0xa0 ); - irr = inb( 0xa0 ) << 8; - outb( 0x0a, 0x20 ); - irr += inb( 0x20 ); - outb( 0x0b, 0xa0 ); - isr = inb( 0xa0 ) << 8; - outb( 0x0b, 0x20 ); - isr += inb( 0x20 ); - - /* Print out interesting information */ - printk( "IMR = 0x%04x", imr ); - if (imr & (1 << interrupt_level)) - printk( " (masked)" ); - printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr ); - - printk( "SCSI Status = 0x%02x\n", inb(port_base + SCSI_Status)); - printk( "TMC Status = 0x%02x", inb(port_base + TMC_Status)); - if (inb((port_base + TMC_Status) & 1)) - printk( " (interrupt)" ); - printk( "\n" ); - printk("Interrupt Status = 0x%02x", inb(port_base + Interrupt_Status)); - if (inb(port_base + Interrupt_Status) & 0x08) - printk( " (enabled)" ); - printk( "\n" ); - if (chip == tmc18c50 || chip == tmc18c30) { - printk("FIFO Status = 0x%02x\n", inb(port_base + FIFO_Status)); - printk( "Int. Condition = 0x%02x\n", - inb( port_base + Interrupt_Cond ) ); - } - printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) ); - if (chip == tmc18c50 || chip == tmc18c30) - printk( "Configuration 2 = 0x%02x\n", - inb( port_base + Configuration2 ) ); -} -#endif - -static int fdomain_16x0_abort(struct scsi_cmnd *SCpnt) -{ -#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT - printk( "scsi: <fdomain> abort " ); -#endif - - if (!in_command) { -#if EVERY_ACCESS || ERRORS_ONLY - printk( " (not in command)\n" ); -#endif - return FAILED; - } else printk( "\n" ); - -#if DEBUG_ABORT - print_info( SCpnt ); -#endif - - fdomain_make_bus_idle(); - current_SC->SCp.phase |= aborted; - current_SC->result = DID_ABORT << 16; - - /* Aborts are not done well. . . */ - my_done(DID_ABORT << 16); - return SUCCESS; -} - -int fdomain_16x0_host_reset(struct scsi_cmnd *SCpnt) -{ - unsigned long flags; - - local_irq_save(flags); - - outb(1, port_base + SCSI_Cntl); - do_pause( 2 ); - outb(0, port_base + SCSI_Cntl); - do_pause( 115 ); - outb(0, port_base + SCSI_Mode_Cntl); - outb(PARITY_MASK, port_base + TMC_Cntl); - - local_irq_restore(flags); - return SUCCESS; -} - -static int fdomain_16x0_biosparam(struct scsi_device *sdev, - struct block_device *bdev, - sector_t capacity, int *info_array) -{ - int drive; - int size = capacity; - unsigned long offset; - struct drive_info { - unsigned short cylinders; - unsigned char heads; - unsigned char sectors; - } i; - - /* NOTES: - The RAM area starts at 0x1f00 from the bios_base address. - - For BIOS Version 2.0: - - The drive parameter table seems to start at 0x1f30. - The first byte's purpose is not known. - Next is the cylinder, head, and sector information. - The last 4 bytes appear to be the drive's size in sectors. - The other bytes in the drive parameter table are unknown. - If anyone figures them out, please send me mail, and I will - update these notes. - - Tape drives do not get placed in this table. - - There is another table at 0x1fea: - If the byte is 0x01, then the SCSI ID is not in use. - If the byte is 0x18 or 0x48, then the SCSI ID is in use, - although tapes don't seem to be in this table. I haven't - seen any other numbers (in a limited sample). - - 0x1f2d is a drive count (i.e., not including tapes) - - The table at 0x1fcc are I/O ports addresses for the various - operations. I calculate these by hand in this driver code. - - - - For the ISA-200S version of BIOS Version 2.0: - - The drive parameter table starts at 0x1f33. - - WARNING: Assume that the table entry is 25 bytes long. Someone needs - to check this for the Quantum ISA-200S card. - - - - For BIOS Version 3.2: - - The drive parameter table starts at 0x1f70. Each entry is - 0x0a bytes long. Heads are one less than we need to report. - */ - - if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) { - printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks"); - return 0; - } - drive = MINOR(bdev->bd_dev) >> 4; - - if (bios_major == 2) { - switch (Quantum) { - case 2: /* ISA_200S */ - /* The value of 25 has never been verified. - It should probably be 15. */ - offset = 0x1f33 + drive * 25; - break; - case 3: /* ISA_250MG */ - offset = 0x1f36 + drive * 15; - break; - case 4: /* ISA_200S (another one) */ - offset = 0x1f34 + drive * 15; - break; - default: - offset = 0x1f31 + drive * 25; - break; - } - memcpy_fromio( &i, bios_mem + offset, sizeof( struct drive_info ) ); - info_array[0] = i.heads; - info_array[1] = i.sectors; - info_array[2] = i.cylinders; - } else if (bios_major == 3 - && bios_minor >= 0 - && bios_minor < 4) { /* 3.0 and 3.2 BIOS */ - memcpy_fromio( &i, bios_mem + 0x1f71 + drive * 10, - sizeof( struct drive_info ) ); - info_array[0] = i.heads + 1; - info_array[1] = i.sectors; - info_array[2] = i.cylinders; - } else { /* 3.4 BIOS (and up?) */ - /* This algorithm was provided by Future Domain (much thanks!). */ - unsigned char *p = scsi_bios_ptable(bdev); - - if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ - && p[4]) { /* Partition type */ - - /* The partition table layout is as follows: - - Start: 0x1b3h - Offset: 0 = partition status - 1 = starting head - 2 = starting sector and cylinder (word, encoded) - 4 = partition type - 5 = ending head - 6 = ending sector and cylinder (word, encoded) - 8 = starting absolute sector (double word) - c = number of sectors (double word) - Signature: 0x1fe = 0x55aa - - So, this algorithm assumes: - 1) the first partition table is in use, - 2) the data in the first entry is correct, and - 3) partitions never divide cylinders - - Note that (1) may be FALSE for NetBSD (and other BSD flavors), - as well as for Linux. Note also, that Linux doesn't pay any - attention to the fields that are used by this algorithm -- it - only uses the absolute sector data. Recent versions of Linux's - fdisk(1) will fill this data in correctly, and forthcoming - versions will check for consistency. - - Checking for a non-zero partition type is not part of the - Future Domain algorithm, but it seemed to be a reasonable thing - to do, especially in the Linux and BSD worlds. */ - - info_array[0] = p[5] + 1; /* heads */ - info_array[1] = p[6] & 0x3f; /* sectors */ - } else { - - /* Note that this new method guarantees that there will always be - less than 1024 cylinders on a platter. This is good for drives - up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */ - - if ((unsigned int)size >= 0x7e0000U) { - info_array[0] = 0xff; /* heads = 255 */ - info_array[1] = 0x3f; /* sectors = 63 */ - } else if ((unsigned int)size >= 0x200000U) { - info_array[0] = 0x80; /* heads = 128 */ - info_array[1] = 0x3f; /* sectors = 63 */ - } else { - info_array[0] = 0x40; /* heads = 64 */ - info_array[1] = 0x20; /* sectors = 32 */ - } - } - /* For both methods, compute the cylinders */ - info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] ); - kfree(p); - } - - return 0; -} - -static int fdomain_16x0_release(struct Scsi_Host *shpnt) -{ - if (shpnt->irq) - free_irq(shpnt->irq, shpnt); - if (shpnt->io_port && shpnt->n_io_port) - release_region(shpnt->io_port, shpnt->n_io_port); - if (PCI_bus) - pci_dev_put(PCI_dev); - return 0; -} - -struct scsi_host_template fdomain_driver_template = { - .module = THIS_MODULE, - .name = "fdomain", - .proc_name = "fdomain", - .detect = fdomain_16x0_detect, - .info = fdomain_16x0_info, - .queuecommand = fdomain_16x0_queue, - .eh_abort_handler = fdomain_16x0_abort, - .eh_host_reset_handler = fdomain_16x0_host_reset, - .bios_param = fdomain_16x0_biosparam, - .release = fdomain_16x0_release, - .can_queue = 1, - .this_id = 6, - .sg_tablesize = 64, - .use_clustering = DISABLE_CLUSTERING, -}; - -#ifndef PCMCIA -#if defined(CONFIG_PCI) && defined(MODULE) - -static struct pci_device_id fdomain_pci_tbl[] = { - { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { } -}; -MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl); -#endif -#define driver_template fdomain_driver_template -#include "scsi_module.c" - -#endif diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h deleted file mode 100644 index 5cbe86b573ae..000000000000 --- a/drivers/scsi/fdomain.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * fdomain.c -- Future Domain TMC-16x0 SCSI driver - * Author: Rickard E. Faith, faith@cs.unc.edu - * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -extern struct scsi_host_template fdomain_driver_template; -extern int fdomain_setup(char *str); -extern struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ); -extern int fdomain_16x0_host_reset(struct scsi_cmnd *SCpnt); diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig index d42f29a5eb65..57183fce70fb 100644 --- a/drivers/scsi/hisi_sas/Kconfig +++ b/drivers/scsi/hisi_sas/Kconfig @@ -1,6 +1,6 @@ config SCSI_HISI_SAS tristate "HiSilicon SAS" - depends on HAS_DMA && HAS_IOMEM + depends on HAS_IOMEM depends on ARM64 || COMPILE_TEST select SCSI_SAS_LIBSAS select BLK_DEV_INTEGRITY diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index e7fd2877c19c..d1153e8e846b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -175,7 +175,6 @@ struct hisi_sas_device { struct hisi_sas_dq *dq; struct list_head list; u64 attached_phy; - atomic64_t running_req; enum sas_device_type dev_type; int device_id; int sata_idx; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 2d4dbed03ee3..49c1fa643803 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -33,7 +33,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) case ATA_CMD_FPDMA_RECV: case ATA_CMD_FPDMA_SEND: case ATA_CMD_NCQ_NON_DATA: - return HISI_SAS_SATA_PROTOCOL_FPDMA; + return HISI_SAS_SATA_PROTOCOL_FPDMA; case ATA_CMD_DOWNLOAD_MICRO: case ATA_CMD_ID_ATA: @@ -45,7 +45,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) case ATA_CMD_WRITE_LOG_EXT: case ATA_CMD_PIO_WRITE: case ATA_CMD_PIO_WRITE_EXT: - return HISI_SAS_SATA_PROTOCOL_PIO; + return HISI_SAS_SATA_PROTOCOL_PIO; case ATA_CMD_DSM: case ATA_CMD_DOWNLOAD_MICRO_DMA: @@ -64,7 +64,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) case ATA_CMD_WRITE_LOG_DMA_EXT: case ATA_CMD_WRITE_STREAM_DMA_EXT: case ATA_CMD_ZAC_MGMT_IN: - return HISI_SAS_SATA_PROTOCOL_DMA; + return HISI_SAS_SATA_PROTOCOL_DMA; case ATA_CMD_CHK_POWER: case ATA_CMD_DEV_RESET: @@ -77,21 +77,21 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) case ATA_CMD_STANDBY: case ATA_CMD_STANDBYNOW1: case ATA_CMD_ZAC_MGMT_OUT: - return HISI_SAS_SATA_PROTOCOL_NONDATA; + return HISI_SAS_SATA_PROTOCOL_NONDATA; default: { if (fis->command == ATA_CMD_SET_MAX) { switch (fis->features) { case ATA_SET_MAX_PASSWD: case ATA_SET_MAX_LOCK: - return HISI_SAS_SATA_PROTOCOL_PIO; + return HISI_SAS_SATA_PROTOCOL_PIO; case ATA_SET_MAX_PASSWD_DMA: case ATA_SET_MAX_UNLOCK_DMA: - return HISI_SAS_SATA_PROTOCOL_DMA; + return HISI_SAS_SATA_PROTOCOL_DMA; default: - return HISI_SAS_SATA_PROTOCOL_NONDATA; + return HISI_SAS_SATA_PROTOCOL_NONDATA; } } if (direction == DMA_NONE) @@ -200,8 +200,6 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, if (task) { struct device *dev = hisi_hba->dev; - struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; if (!task->lldd_task) return; @@ -213,9 +211,6 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, dma_unmap_sg(dev, task->scatter, task->num_scatter, task->data_dir); - - if (sas_dev) - atomic64_dec(&sas_dev->running_req); } if (slot->buf) @@ -321,7 +316,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq */ if (device->dev_type != SAS_SATA_DEV) task->task_done(task); - return SAS_PHY_DOWN; + return -ECOMM; } if (DEV_IS_GONE(sas_dev)) { @@ -332,7 +327,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq dev_info(dev, "task prep: device %016llx not ready\n", SAS_ADDR(device->sas_addr)); - return SAS_PHY_DOWN; + return -ECOMM; } port = to_hisi_sas_port(sas_port); @@ -342,7 +337,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq "SATA/STP" : "SAS", device->port->id); - return SAS_PHY_DOWN; + return -ECOMM; } if (!sas_protocol_ata(task->task_proto)) { @@ -431,8 +426,6 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq spin_unlock_irqrestore(&task->task_state_lock, flags); dq->slot_prep = slot; - - atomic64_inc(&sas_dev->running_req); ++(*pass); return 0; @@ -683,6 +676,8 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no) phy->hisi_hba = hisi_hba; phy->port = NULL; + phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; + phy->maximum_linkrate = hisi_hba->hw->phy_get_max_linkrate(); sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0; sas_phy->class = SAS; sas_phy->iproto = SAS_PROTOCOL_ALL; @@ -869,6 +864,7 @@ static void hisi_sas_tmf_timedout(struct timer_list *t) #define TASK_TIMEOUT 20 #define TASK_RETRY 3 +#define INTERNAL_ABORT_TIMEOUT 6 static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, void *parameter, u32 para_len, struct hisi_sas_tmf_task *tmf) @@ -1514,8 +1510,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, dq->slot_prep = slot; - atomic64_inc(&sas_dev->running_req); - /* send abort command to the chip */ hisi_hba->hw->start_delivery(dq); spin_unlock_irqrestore(&dq->lock, flags_dq); @@ -1572,7 +1566,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, task->task_proto = device->tproto; task->task_done = hisi_sas_task_done; task->slow_task->timer.function = hisi_sas_tmf_timedout; - task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110); + task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT*HZ; add_timer(&task->slow_task->timer); res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 679e76f58a0a..84a0ccc4daf5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -651,8 +651,10 @@ static int reset_hw_v1_hw(struct hisi_hba *hisi_hba) dev_err(dev, "De-reset failed\n"); return -EIO; } - } else + } else { dev_warn(dev, "no reset method\n"); + return -EINVAL; + } return 0; } @@ -873,7 +875,6 @@ static void phy_set_linkrate_v1_hw(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->maximum_linkrate = max; sas_phy->phy->minimum_linkrate = min; - min -= SAS_LINK_RATE_1_5_GBPS; max -= SAS_LINK_RATE_1_5_GBPS; for (i = 0; i <= max; i++) @@ -882,10 +883,11 @@ static void phy_set_linkrate_v1_hw(struct hisi_hba *hisi_hba, int phy_no, prog_phy_link_rate &= ~0xff; prog_phy_link_rate |= rate_mask; + disable_phy_v1_hw(hisi_hba, phy_no); + msleep(100); hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, prog_phy_link_rate); - - phy_hard_reset_v1_hw(hisi_hba, phy_no); + start_phy_v1_hw(hisi_hba, phy_no); } static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id) @@ -1407,9 +1409,6 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, } out: - if (sas_dev) - atomic64_dec(&sas_dev->running_req); - hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 4ccb61e2ae5c..f89fb9a49ea9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -406,6 +406,17 @@ struct hisi_sas_err_record_v2 { __le32 dma_rx_err_type; }; +struct signal_attenuation_s { + u32 de_emphasis; + u32 preshoot; + u32 boost; +}; + +struct sig_atten_lu_s { + const struct signal_attenuation_s *att; + u32 sas_phy_ctrl; +}; + static const struct hisi_sas_hw_error one_bit_ecc_errors[] = { { .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF), @@ -1084,8 +1095,10 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba) dev_err(dev, "SAS de-reset fail.\n"); return -EIO; } - } else - dev_warn(dev, "no reset method\n"); + } else { + dev_err(dev, "no reset method\n"); + return -EINVAL; + } return 0; } @@ -1130,9 +1143,16 @@ static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba) } } +static const struct signal_attenuation_s x6000 = {9200, 0, 10476}; +static const struct sig_atten_lu_s sig_atten_lu[] = { + { &x6000, 0x3016a68 }, +}; + static void init_reg_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; + u32 sas_phy_ctrl = 0x30b9908; + u32 signal[3]; int i; /* Global registers init */ @@ -1176,9 +1196,28 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1); hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1); + /* Get sas_phy_ctrl value to deal with TX FFE issue. */ + if (!device_property_read_u32_array(dev, "hisilicon,signal-attenuation", + signal, ARRAY_SIZE(signal))) { + for (i = 0; i < ARRAY_SIZE(sig_atten_lu); i++) { + const struct sig_atten_lu_s *lookup = &sig_atten_lu[i]; + const struct signal_attenuation_s *att = lookup->att; + + if ((signal[0] == att->de_emphasis) && + (signal[1] == att->preshoot) && + (signal[2] == att->boost)) { + sas_phy_ctrl = lookup->sas_phy_ctrl; + break; + } + } + + if (i == ARRAY_SIZE(sig_atten_lu)) + dev_warn(dev, "unknown signal attenuation values, using default PHY ctrl config\n"); + } + for (i = 0; i < hisi_hba->n_phy; i++) { hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); - hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908); + hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl); hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d); hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0); hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2); @@ -1566,7 +1605,6 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->maximum_linkrate = max; sas_phy->phy->minimum_linkrate = min; - min -= SAS_LINK_RATE_1_5_GBPS; max -= SAS_LINK_RATE_1_5_GBPS; for (i = 0; i <= max; i++) @@ -1575,10 +1613,11 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no, prog_phy_link_rate &= ~0xff; prog_phy_link_rate |= rate_mask; + disable_phy_v2_hw(hisi_hba, phy_no); + msleep(100); hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, prog_phy_link_rate); - - phy_hard_reset_v2_hw(hisi_hba, phy_no); + start_phy_v2_hw(hisi_hba, phy_no); } static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id) @@ -2371,7 +2410,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, slot); spin_unlock_irqrestore(&hisi_hba->lock, flags); - return -1; + return ts->stat; } if (unlikely(!sas_dev)) { @@ -2630,7 +2669,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, /* dw0 */ hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ (port->id << CMD_HDR_PORT_OFF) | - ((dev_is_sata(dev) ? 1:0) << + (dev_is_sata(dev) << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | (abort_flag << CMD_HDR_ABORT_FLAG_OFF)); @@ -2647,7 +2686,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = IRQ_HANDLED; - u32 port_id, link_rate, hard_phy_linkrate; + u32 port_id, link_rate; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct device *dev = hisi_hba->dev; @@ -2686,11 +2725,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) } sas_phy->linkrate = link_rate; - hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no, - HARD_PHY_LINKRATE); - phy->maximum_linkrate = hard_phy_linkrate & 0xf; - phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf; - sas_phy->oob_mode = SAS_OOB_MODE; memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE); dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index a1f18689729a..6f3e5ba6b472 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -172,6 +172,7 @@ #define CHL_INT1_MSK (PORT_BASE + 0x1c4) #define CHL_INT2_MSK (PORT_BASE + 0x1c8) #define CHL_INT_COAL_EN (PORT_BASE + 0x1d0) +#define SAS_RX_TRAIN_TIMER (PORT_BASE + 0x2a4) #define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0) #define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4) #define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8) @@ -184,6 +185,8 @@ #define DMA_RX_STATUS (PORT_BASE + 0x2e8) #define DMA_RX_STATUS_BUSY_OFF 0 #define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF) + +#define COARSETUNE_TIME (PORT_BASE + 0x304) #define ERR_CNT_DWS_LOST (PORT_BASE + 0x380) #define ERR_CNT_RESET_PROB (PORT_BASE + 0x384) #define ERR_CNT_INVLD_DW (PORT_BASE + 0x390) @@ -340,12 +343,6 @@ struct hisi_sas_err_record_v3 { #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096 #define HISI_SAS_MSI_COUNT_V3_HW 32 -enum { - HISI_SAS_PHY_PHY_UPDOWN, - HISI_SAS_PHY_CHNL_INT, - HISI_SAS_PHY_INT_NR -}; - #define DIR_NO_DATA 0 #define DIR_TO_INI 1 #define DIR_TO_DEVICE 2 @@ -423,10 +420,10 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0); hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1); - hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE, 0x30000); for (i = 0; i < hisi_hba->n_phy; i++) { - hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x801); + hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); + hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80); hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff); @@ -438,17 +435,13 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0); - hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0); - hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199b4fa); - hisi_sas_phy_write32(hisi_hba, i, SAS_SSP_CON_TIMER_CFG, - 0xa03e8); - hisi_sas_phy_write32(hisi_hba, i, SAS_STP_CON_TIMER_CFG, - 0xa03e8); - hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, - 0x7f7a120); - hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, - 0x2a0a80); + hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1); + hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120); + + /* used for 12G negotiate */ + hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e); } + for (i = 0; i < hisi_hba->queue_count; i++) { /* Delivery queue */ hisi_sas_write32(hisi_hba, @@ -676,8 +669,10 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba) dev_err(dev, "Reset failed\n"); return -EIO; } - } else + } else { dev_err(dev, "no reset method!\n"); + return -EINVAL; + } return 0; } @@ -737,7 +732,7 @@ static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no) start_phy_v3_hw(hisi_hba, phy_no); } -enum sas_linkrate phy_get_max_linkrate_v3_hw(void) +static enum sas_linkrate phy_get_max_linkrate_v3_hw(void) { return SAS_LINK_RATE_12_0_GBPS; } @@ -1102,7 +1097,7 @@ static int prep_abort_v3_hw(struct hisi_hba *hisi_hba, /* dw0 */ hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ (port->id << CMD_HDR_PORT_OFF) | - ((dev_is_sata(dev) ? 1:0) + (dev_is_sata(dev) << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | (abort_flag << CMD_HDR_ABORT_FLAG_OFF)); @@ -1118,10 +1113,10 @@ static int prep_abort_v3_hw(struct hisi_hba *hisi_hba, return 0; } -static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) { - int i, res = 0; - u32 context, port_id, link_rate, hard_phy_linkrate; + int i, res; + u32 context, port_id, link_rate; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct device *dev = hisi_hba->dev; @@ -1139,10 +1134,6 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) goto end; } sas_phy->linkrate = link_rate; - hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no, - HARD_PHY_LINKRATE); - phy->maximum_linkrate = hard_phy_linkrate & 0xf; - phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf; phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); /* Check for SATA dev */ @@ -1196,7 +1187,7 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) phy->port_id = port_id; phy->phy_attached = 1; hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); - + res = IRQ_HANDLED; end: hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_PHY_ENABLE_MSK); @@ -1205,7 +1196,7 @@ end: return res; } -static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) { u32 phy_state, sl_ctrl, txid_auto; struct device *dev = hisi_hba->dev; @@ -1227,10 +1218,10 @@ static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0); - return 0; + return IRQ_HANDLED; } -static void phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +static irqreturn_t phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba) { struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; @@ -1241,6 +1232,8 @@ static void phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_RX_BCST_ACK_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0); + + return IRQ_HANDLED; } static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) @@ -1267,7 +1260,9 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) res = IRQ_HANDLED; if (irq_value & CHL_INT0_SL_RX_BCST_ACK_MSK) /* phy bcast */ - phy_bcast_v3_hw(phy_no, hisi_hba); + if (phy_bcast_v3_hw(phy_no, hisi_hba) + == IRQ_HANDLED) + res = IRQ_HANDLED; } else { if (irq_value & CHL_INT0_NOT_RDY_MSK) /* phy down */ @@ -1583,7 +1578,7 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, slot); spin_unlock_irqrestore(&hisi_hba->lock, flags); - return -1; + return ts->stat; } if (unlikely(!sas_dev)) { @@ -1864,7 +1859,6 @@ static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->maximum_linkrate = max; sas_phy->phy->minimum_linkrate = min; - min -= SAS_LINK_RATE_1_5_GBPS; max -= SAS_LINK_RATE_1_5_GBPS; for (i = 0; i <= max; i++) @@ -1873,10 +1867,11 @@ static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no, prog_phy_link_rate &= ~0xff; prog_phy_link_rate |= rate_mask; + disable_phy_v3_hw(hisi_hba, phy_no); + msleep(100); hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, prog_phy_link_rate); - - phy_hard_reset_v3_hw(hisi_hba, phy_no); + start_phy_v3_hw(hisi_hba, phy_no); } static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba) @@ -2399,6 +2394,7 @@ static const struct pci_device_id sas_v3_pci_table[] = { { PCI_VDEVICE(HUAWEI, 0xa230), hip08 }, {} }; +MODULE_DEVICE_TABLE(pci, sas_v3_pci_table); static const struct pci_error_handlers hisi_sas_err_handler = { .error_detected = hisi_sas_error_detected_v3_hw, @@ -2421,4 +2417,4 @@ module_pci_driver(sas_v3_pci_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Garry <john.garry@huawei.com>"); MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device"); -MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("pci:" DRV_NAME); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index ef22b275d050..7649d63a1b8d 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -42,6 +42,12 @@ #include "scsi_logging.h" +static int shost_eh_deadline = -1; + +module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(eh_deadline, + "SCSI EH timeout in seconds (should be between 0 and 2^31-1)"); + static DEFINE_IDA(host_index_ida); @@ -148,7 +154,6 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) scsi_host_state_name(state))); return -EINVAL; } -EXPORT_SYMBOL(scsi_host_set_state); /** * scsi_remove_host - remove a scsi host @@ -356,12 +361,6 @@ static void scsi_host_dev_release(struct device *dev) kfree(shost); } -static int shost_eh_deadline = -1; - -module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(eh_deadline, - "SCSI EH timeout in seconds (should be between 0 and 2^31-1)"); - static struct device_type scsi_host_type = { .name = "scsi_host", .release = scsi_host_dev_release, @@ -517,29 +516,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) } EXPORT_SYMBOL(scsi_host_alloc); -struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize) -{ - struct Scsi_Host *shost = scsi_host_alloc(sht, privsize); - - if (!sht->detect) { - printk(KERN_WARNING "scsi_register() called on new-style " - "template for driver %s\n", sht->name); - dump_stack(); - } - - if (shost) - list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts); - return shost; -} -EXPORT_SYMBOL(scsi_register); - -void scsi_unregister(struct Scsi_Host *shost) -{ - list_del(&shost->sht_legacy_list); - scsi_host_put(shost); -} -EXPORT_SYMBOL(scsi_unregister); - static int __scsi_host_match(struct device *dev, const void *data) { struct Scsi_Host *p; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e07dd990e585..dda1a64ab89c 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3816,10 +3816,8 @@ static struct device_attribute ipr_iopoll_weight_attr = { **/ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) { - int sg_size, order, bsize_elem, num_elem, i, j; + int sg_size, order; struct ipr_sglist *sglist; - struct scatterlist *scatterlist; - struct page *page; /* Get the minimum size per scatter/gather element */ sg_size = buf_len / (IPR_MAX_SGLIST - 1); @@ -3827,45 +3825,18 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) /* Get the actual size per element */ order = get_order(sg_size); - /* Determine the actual number of bytes per element */ - bsize_elem = PAGE_SIZE * (1 << order); - - /* Determine the actual number of sg entries needed */ - if (buf_len % bsize_elem) - num_elem = (buf_len / bsize_elem) + 1; - else - num_elem = buf_len / bsize_elem; - /* Allocate a scatter/gather list for the DMA */ - sglist = kzalloc(sizeof(struct ipr_sglist) + - (sizeof(struct scatterlist) * (num_elem - 1)), - GFP_KERNEL); - + sglist = kzalloc(sizeof(struct ipr_sglist), GFP_KERNEL); if (sglist == NULL) { ipr_trace; return NULL; } - - scatterlist = sglist->scatterlist; - sg_init_table(scatterlist, num_elem); - sglist->order = order; - sglist->num_sg = num_elem; - - /* Allocate a bunch of sg elements */ - for (i = 0; i < num_elem; i++) { - page = alloc_pages(GFP_KERNEL, order); - if (!page) { - ipr_trace; - - /* Free up what we already allocated */ - for (j = i - 1; j >= 0; j--) - __free_pages(sg_page(&scatterlist[j]), order); - kfree(sglist); - return NULL; - } - - sg_set_page(&scatterlist[i], page, 0, 0); + sglist->scatterlist = sgl_alloc_order(buf_len, order, false, GFP_KERNEL, + &sglist->num_sg); + if (!sglist->scatterlist) { + kfree(sglist); + return NULL; } return sglist; @@ -3883,11 +3854,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) **/ static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) { - int i; - - for (i = 0; i < sglist->num_sg; i++) - __free_pages(sg_page(&sglist->scatterlist[i]), sglist->order); - + sgl_free_order(sglist->scatterlist, sglist->order); kfree(sglist); } @@ -9684,14 +9651,14 @@ static int ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) } for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { - ipr_cmd = dma_pool_alloc(ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); + ipr_cmd = dma_pool_zalloc(ioa_cfg->ipr_cmd_pool, + GFP_KERNEL, &dma_addr); if (!ipr_cmd) { ipr_free_cmd_blks(ioa_cfg); return -ENOMEM; } - memset(ipr_cmd, 0, sizeof(*ipr_cmd)); ioa_cfg->ipr_cmnd_list[i] = ipr_cmd; ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index c7f0e9e3cd7d..93570734cbfb 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1454,7 +1454,7 @@ struct ipr_sglist { u32 num_sg; u32 num_dma_sg; u32 buffer_len; - struct scatterlist scatterlist[1]; + struct scatterlist *scatterlist; }; enum ipr_sdt_state { diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 67621308eb9c..e3c8857741a1 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -224,8 +224,6 @@ module_param(ips, charp, 0); /* * Function prototypes */ -static int ips_detect(struct scsi_host_template *); -static int ips_release(struct Scsi_Host *); static int ips_eh_abort(struct scsi_cmnd *); static int ips_eh_reset(struct scsi_cmnd *); static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); @@ -355,8 +353,6 @@ static dma_addr_t ips_flashbusaddr; static long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */ static uint32_t MaxLiteCmds = 32; /* Max Active Cmds for a Lite Adapter */ static struct scsi_host_template ips_driver_template = { - .detect = ips_detect, - .release = ips_release, .info = ips_info, .queuecommand = ips_queue, .eh_abort_handler = ips_eh_abort, diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 13b37cdffa8e..1ee3868ade07 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -2766,7 +2766,7 @@ static int sci_write_gpio_tx_gp(struct isci_host *ihost, u8 reg_index, u8 reg_co int i; for (i = 0; i < 3; i++) { - int bit = (i << 2) + 2; + int bit; bit = try_test_sas_gpio_gp_bit(to_sas_gpio_od(d, i), write_data, reg_index, diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 9aaa74e349cc..6eb5ff3e2e61 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -147,7 +147,7 @@ static int esp_jazz_probe(struct platform_device *dev) esp = shost_priv(host); esp->host = host; - esp->dev = dev; + esp->dev = &dev->dev; esp->ops = &jazz_esp_ops; res = platform_get_resource(dev, IORESOURCE_MEM, 0); diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 8660f923ace0..3f3569ec5ce3 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -731,7 +731,7 @@ static void fc_disc_stop_final(struct fc_lport *lport) */ void fc_disc_config(struct fc_lport *lport, void *priv) { - struct fc_disc *disc = &lport->disc; + struct fc_disc *disc; if (!lport->tt.disc_start) lport->tt.disc_start = fc_disc_start; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 2b3637b40dde..0cc1567eacc1 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -709,7 +709,7 @@ void sas_resume_sata(struct asd_sas_port *port) } /** - * sas_discover_sata -- discover an STP/SATA domain device + * sas_discover_sata - discover an STP/SATA domain device * @dev: pointer to struct domain_device of interest * * Devices directly attached to a HA port, have no parents. All other diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index e4fd078e4175..a0fa7ef3a071 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -55,7 +55,7 @@ void sas_init_dev(struct domain_device *dev) /* ---------- Domain device discovery ---------- */ /** - * sas_get_port_device -- Discover devices which caused port creation + * sas_get_port_device - Discover devices which caused port creation * @port: pointer to struct sas_port of interest * * Devices directly attached to a HA port, have no parent. This is @@ -278,8 +278,8 @@ static void sas_resume_devices(struct work_struct *work) } /** - * sas_discover_end_dev -- discover an end device (SSP, etc) - * @end: pointer to domain device of interest + * sas_discover_end_dev - discover an end device (SSP, etc) + * @dev: pointer to domain device of interest * * See comment in sas_discover_sata(). */ @@ -428,8 +428,8 @@ void sas_device_set_phy(struct domain_device *dev, struct sas_port *port) /* ---------- Discovery and Revalidation ---------- */ /** - * sas_discover_domain -- discover the domain - * @port: port to the domain of interest + * sas_discover_domain - discover the domain + * @work: work structure embedded in port domain device. * * NOTE: this process _must_ quit (return) as soon as any connection * errors are encountered. Connection recovery is done elsewhere. @@ -572,7 +572,8 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) } /** - * sas_init_disc -- initialize the discovery struct in the port + * sas_init_disc - initialize the discovery struct in the port + * @disc: port discovery structure * @port: pointer to struct port * * Called when the ports are being initialized. diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 6a4f8198b78e..8b7114348def 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1170,9 +1170,9 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev) return 0; } /** - * sas_ex_discover_devices -- discover devices attached to this expander - * dev: pointer to the expander domain device - * single: if you want to do a single phy, else set to -1; + * sas_ex_discover_devices - discover devices attached to this expander + * @dev: pointer to the expander domain device + * @single: if you want to do a single phy, else set to -1; * * Configure this expander for use with its devices and register the * devices of this expander. @@ -1528,10 +1528,11 @@ static int sas_configure_phy(struct domain_device *dev, int phy_id, } /** - * sas_configure_parent -- configure routing table of parent - * parent: parent expander - * child: child expander - * sas_addr: SAS port identifier of device directly attached to child + * sas_configure_parent - configure routing table of parent + * @parent: parent expander + * @child: child expander + * @sas_addr: SAS port identifier of device directly attached to child + * @include: whether or not to include @child in the expander routing table */ static int sas_configure_parent(struct domain_device *parent, struct domain_device *child, @@ -1570,9 +1571,9 @@ static int sas_configure_parent(struct domain_device *parent, } /** - * sas_configure_routing -- configure routing - * dev: expander device - * sas_addr: port identifier of device directly attached to the expander device + * sas_configure_routing - configure routing + * @dev: expander device + * @sas_addr: port identifier of device directly attached to the expander device */ static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr) { @@ -1589,8 +1590,8 @@ static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr) } /** - * sas_discover_expander -- expander discovery - * @ex: pointer to expander domain device + * sas_discover_expander - expander discovery + * @dev: pointer to expander domain device * * See comment in sas_discover_sata(). */ @@ -2111,8 +2112,8 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id) } /** - * sas_revalidate_domain -- revalidate the domain - * @port: port to the domain of interest + * sas_ex_revalidate_domain - revalidate the domain + * @port_dev: port domain device. * * NOTE: this process _must_ quit (return) as soon as any connection * errors are encountered. Connection recovery is done elsewhere. diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index c81a63b5dc71..ede0af78144f 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -234,7 +234,7 @@ int sas_try_ata_reset(struct asd_sas_phy *asd_phy) return -ENODEV; } -/** +/* * transport_sas_phy_reset - reset a phy and permit libata to manage the link * * phy reset request via sysfs in host workqueue context so we know we diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index f07e55d3aa73..fad23dd39114 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -84,7 +84,7 @@ static void sas_resume_port(struct asd_sas_phy *phy) } /** - * sas_form_port -- add this phy to a port + * sas_form_port - add this phy to a port * @phy: the phy of interest * * This function adds this phy to an existing port, thus creating a wide @@ -197,8 +197,9 @@ static void sas_form_port(struct asd_sas_phy *phy) } /** - * sas_deform_port -- remove this phy from the port it belongs to + * sas_deform_port - remove this phy from the port it belongs to * @phy: the phy of interest + * @gone: whether or not the PHY is gone * * This is called when the physical link to the other phy has been * lost (on this phy), in Event thread context. We cannot delay here. diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 61fb46da05d4..6c0d351c0d0d 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -544,16 +544,10 @@ struct unsol_rcv_ct_ctx { #define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */ #define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */ #define LPFC_USER_LINK_SPEED_32G 32 /* 32 Gigabaud */ -#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_32G -#define LPFC_USER_LINK_SPEED_BITMAP ((1ULL << LPFC_USER_LINK_SPEED_32G) | \ - (1 << LPFC_USER_LINK_SPEED_16G) | \ - (1 << LPFC_USER_LINK_SPEED_10G) | \ - (1 << LPFC_USER_LINK_SPEED_8G) | \ - (1 << LPFC_USER_LINK_SPEED_4G) | \ - (1 << LPFC_USER_LINK_SPEED_2G) | \ - (1 << LPFC_USER_LINK_SPEED_1G) | \ - (1 << LPFC_USER_LINK_SPEED_AUTO)) -#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32" +#define LPFC_USER_LINK_SPEED_64G 64 /* 64 Gigabaud */ +#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_64G + +#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32, 64" enum nemb_type { nemb_mse = 1, @@ -760,6 +754,7 @@ struct lpfc_hba { uint8_t mds_diags_support; uint32_t initial_imax; uint8_t bbcredit_support; + uint8_t enab_exp_wqcq_pages; /* HBA Config Parameters */ uint32_t cfg_ack0; @@ -787,6 +782,7 @@ struct lpfc_hba { uint32_t cfg_fcp_io_channel; uint32_t cfg_suppress_rsp; uint32_t cfg_nvme_oas; + uint32_t cfg_nvme_embed_cmd; uint32_t cfg_nvme_io_channel; uint32_t cfg_nvmet_mrq; uint32_t cfg_enable_nvmet; @@ -839,11 +835,14 @@ struct lpfc_hba { uint32_t cfg_enable_SmartSAN; uint32_t cfg_enable_mds_diags; uint32_t cfg_enable_fc4_type; - uint32_t cfg_enable_bbcr; /*Enable BB Credit Recovery*/ + uint32_t cfg_enable_bbcr; /* Enable BB Credit Recovery */ + uint32_t cfg_enable_dpp; /* Enable Direct Packet Push */ uint32_t cfg_xri_split; #define LPFC_ENABLE_FCP 1 #define LPFC_ENABLE_NVME 2 #define LPFC_ENABLE_BOTH 3 + uint32_t nvme_embed_pbde; + uint32_t fcp_embed_pbde; uint32_t io_channel_irqs; /* number of irqs for io channels */ struct nvmet_fc_target_port *targetport; lpfc_vpd_t vpd; /* vital product data */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index ac77081e6e9e..2ac1d21c553f 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -259,6 +259,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, atomic_read(&tgtp->xmt_abort_rsp), atomic_read(&tgtp->xmt_abort_rsp_error)); + len += snprintf(buf + len, PAGE_SIZE - len, + "DELAY: ctx %08x fod %08x wqfull %08x\n", + atomic_read(&tgtp->defer_ctx), + atomic_read(&tgtp->defer_fod), + atomic_read(&tgtp->defer_wqfull)); + /* Calculate outstanding IOs */ tot = atomic_read(&tgtp->rcv_fcp_cmd_drop); tot += atomic_read(&tgtp->xmt_fcp_release); @@ -905,7 +911,12 @@ lpfc_issue_lip(struct Scsi_Host *shost) LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; + /* + * If the link is offline, disabled or BLOCK_MGMT_IO + * it doesn't make any sense to allow issue_lip + */ if ((vport->fc_flag & FC_OFFLINE_MODE) || + (phba->hba_flag & LINK_DISABLED) || (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; @@ -3458,8 +3469,8 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512, # tgt_queue_depth: This parameter is used to limit the number of outstanding # commands per target port. Value range is [10,65535]. Default value is 65535. */ -LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535, - "Max number of FCP commands we can queue to a specific target port"); +LPFC_VPORT_ATTR_RW(tgt_queue_depth, 65535, 10, 65535, + "Max number of FCP commands we can queue to a specific target port"); /* # hba_queue_depth: This parameter is used to limit the number of outstanding @@ -4104,23 +4115,32 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) || - ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb))) { + ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb)) || + ((val == LPFC_USER_LINK_SPEED_64G) && !(phba->lmt & LMT_64Gb))) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2879 lpfc_link_speed attribute cannot be set " "to %d. Speed is not supported by this port.\n", val); return -EINVAL; } - if (val == LPFC_USER_LINK_SPEED_16G && - phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + if (val >= LPFC_USER_LINK_SPEED_16G && + phba->fc_topology == LPFC_TOPOLOGY_LOOP) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3112 lpfc_link_speed attribute cannot be set " "to %d. Speed is not supported in loop mode.\n", val); return -EINVAL; } - if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && - (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { + + switch (val) { + case LPFC_USER_LINK_SPEED_AUTO: + case LPFC_USER_LINK_SPEED_1G: + case LPFC_USER_LINK_SPEED_2G: + case LPFC_USER_LINK_SPEED_4G: + case LPFC_USER_LINK_SPEED_8G: + case LPFC_USER_LINK_SPEED_16G: + case LPFC_USER_LINK_SPEED_32G: + case LPFC_USER_LINK_SPEED_64G: prev_val = phba->cfg_link_speed; phba->cfg_link_speed = val; if (nolip) @@ -4130,13 +4150,18 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, if (err) { phba->cfg_link_speed = prev_val; return -EINVAL; - } else - return strlen(buf); + } + return strlen(buf); + default: + break; } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0469 lpfc_link_speed attribute cannot be set to %d, " - "allowed values are ["LPFC_LINK_SPEED_STRING"]\n", val); + "0469 lpfc_link_speed attribute cannot be set to %d, " + "allowed values are [%s]\n", + val, LPFC_LINK_SPEED_STRING); return -EINVAL; + } static int lpfc_link_speed = 0; @@ -4163,24 +4188,33 @@ lpfc_param_show(link_speed) static int lpfc_link_speed_init(struct lpfc_hba *phba, int val) { - if (val == LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) { + if (val >= LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3111 lpfc_link_speed of %d cannot " "support loop mode, setting topology to default.\n", val); phba->cfg_topology = 0; } - if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && - (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { + + switch (val) { + case LPFC_USER_LINK_SPEED_AUTO: + case LPFC_USER_LINK_SPEED_1G: + case LPFC_USER_LINK_SPEED_2G: + case LPFC_USER_LINK_SPEED_4G: + case LPFC_USER_LINK_SPEED_8G: + case LPFC_USER_LINK_SPEED_16G: + case LPFC_USER_LINK_SPEED_32G: + case LPFC_USER_LINK_SPEED_64G: phba->cfg_link_speed = val; return 0; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0405 lpfc_link_speed attribute cannot " + "be set to %d, allowed values are " + "["LPFC_LINK_SPEED_STRING"]\n", val); + phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; + return -EINVAL; } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0405 lpfc_link_speed attribute cannot " - "be set to %d, allowed values are " - "["LPFC_LINK_SPEED_STRING"]\n", val); - phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; - return -EINVAL; } static DEVICE_ATTR_RW(lpfc_link_speed); @@ -5008,6 +5042,18 @@ LPFC_ATTR_RW(nvme_oas, 0, 0, 1, "Use OAS bit on NVME IOs"); /* + * lpfc_nvme_embed_cmd: Use the oas bit when sending NVME/NVMET IOs + * + * 0 = Put NVME Command in SGL + * 1 = Embed NVME Command in WQE (unless G7) + * 2 = Embed NVME Command in WQE (force) + * + * Value range is [0,2]. Default value is 1. + */ +LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2, + "Embed NVME Command in WQE"); + +/* * lpfc_fcp_io_channel: Set the number of FCP IO channels the driver * will advertise it supports to the SCSI layer. This also will map to * the number of WQs the driver will create. @@ -5175,6 +5221,14 @@ LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); */ LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery"); +/* + * lpfc_enable_dpp: Enable DPP on G7 + * 0 = DPP on G7 disabled + * 1 = DPP on G7 enabled (default) + * Value range is [0,1]. Default value is 1. + */ +LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push"); + struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_nvme_info, &dev_attr_bg_info, @@ -5240,6 +5294,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_task_mgmt_tmo, &dev_attr_lpfc_use_msi, &dev_attr_lpfc_nvme_oas, + &dev_attr_lpfc_nvme_embed_cmd, &dev_attr_lpfc_auto_imax, &dev_attr_lpfc_fcp_imax, &dev_attr_lpfc_fcp_cpu_map, @@ -5283,6 +5338,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_xlane_supported, &dev_attr_lpfc_enable_mds_diags, &dev_attr_lpfc_enable_bbcr, + &dev_attr_lpfc_enable_dpp, NULL, }; @@ -5696,6 +5752,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost) case LPFC_LINK_SPEED_32GHZ: fc_host_speed(shost) = FC_PORTSPEED_32GBIT; break; + case LPFC_LINK_SPEED_64GHZ: + fc_host_speed(shost) = FC_PORTSPEED_64GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; @@ -6260,6 +6319,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN); lpfc_use_msi_init(phba, lpfc_use_msi); lpfc_nvme_oas_init(phba, lpfc_nvme_oas); + lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd); lpfc_auto_imax_init(phba, lpfc_auto_imax); lpfc_fcp_imax_init(phba, lpfc_fcp_imax); lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map); @@ -6284,6 +6344,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_poll = 0; else phba->cfg_poll = lpfc_poll; + + if (phba->cfg_enable_bg) + phba->sli3_options |= LPFC_SLI3_BG_ENABLED; + lpfc_suppress_rsp_init(phba, lpfc_suppress_rsp); lpfc_enable_fc4_type_init(phba, lpfc_enable_fc4_type); @@ -6295,6 +6359,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel); lpfc_nvme_io_channel_init(phba, lpfc_nvme_io_channel); lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr); + lpfc_enable_dpp_init(phba, lpfc_enable_dpp); if (phba->sli_rev != LPFC_SLI_REV4) { /* NVME only supported on SLI4 */ diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d89816222b23..0f174ca80f67 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -3867,7 +3867,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, "ext_buf_cnt:%d\n", ext_buf_cnt); } else { /* sanity check on interface type for support */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < LPFC_SLI_INTF_IF_TYPE_2) { rc = -ENODEV; goto job_error; @@ -4053,7 +4053,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, "ext_buf_cnt:%d\n", ext_buf_cnt); } else { /* sanity check on interface type for support */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < LPFC_SLI_INTF_IF_TYPE_2) return -ENODEV; /* nemb_tp == nemb_hbd */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 559f9aa0ed08..4ae9ba425e78 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -254,6 +254,7 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctxp); int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct fc_frame_header *fc_hdr); +void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq); void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba); void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba); void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *, @@ -564,6 +565,8 @@ void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba); void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_wcqe_complete *abts_cmpl); +void lpfc_nvme_cmd_template(void); +void lpfc_nvmet_cmd_template(void); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; extern int lpfc_no_hba_reset_cnt; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 9d20d2c208c7..0617c8ea88c6 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -471,7 +471,6 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) "Parse GID_FTrsp: did:x%x flg:x%x x%x", Did, ndlp->nlp_flag, vport->fc_flag); - ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); /* By default, the driver expects to support FCP FC4 */ if (fc4_type == FC_TYPE_FCP) ndlp->nlp_fc4_type |= NLP_FC4_FCP; @@ -2130,6 +2129,8 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, ae->un.AttrInt = 0; if (!(phba->hba_flag & HBA_FCOE_MODE)) { + if (phba->lmt & LMT_64Gb) + ae->un.AttrInt |= HBA_PORTSPEED_64GFC; if (phba->lmt & LMT_32Gb) ae->un.AttrInt |= HBA_PORTSPEED_32GFC; if (phba->lmt & LMT_16Gb) @@ -2201,6 +2202,9 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, case LPFC_LINK_SPEED_32GHZ: ae->un.AttrInt = HBA_PORTSPEED_32GFC; break; + case LPFC_LINK_SPEED_64GHZ: + ae->un.AttrInt = HBA_PORTSPEED_64GFC; + break; default: ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 17ea3bb04266..fb0dc2aeed91 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -3944,10 +3944,15 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, return 0; switch (drbregid) { - case LPFC_DRB_EQCQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, - "EQCQ-DRB-REG: 0x%08x\n", - readl(phba->sli4_hba.EQCQDBregaddr)); + case LPFC_DRB_EQ: + len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len, + "EQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.EQDBregaddr)); + break; + case LPFC_DRB_CQ: + len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len, + "CQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.CQDBregaddr)); break; case LPFC_DRB_MQ: len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, @@ -4086,8 +4091,11 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { switch (drb_reg_id) { - case LPFC_DRB_EQCQ: - drb_reg = phba->sli4_hba.EQCQDBregaddr; + case LPFC_DRB_EQ: + drb_reg = phba->sli4_hba.EQDBregaddr; + break; + case LPFC_DRB_CQ: + drb_reg = phba->sli4_hba.CQDBregaddr; break; case LPFC_DRB_MQ: drb_reg = phba->sli4_hba.MQDBregaddr; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index c4edd87bfc65..f32eaeb2225a 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2007-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -126,12 +126,13 @@ #define LPFC_DRB_ACC_WR_CMD_ARG 2 #define LPFC_DRB_ACC_BUF_SIZE 256 -#define LPFC_DRB_EQCQ 1 -#define LPFC_DRB_MQ 2 -#define LPFC_DRB_WQ 3 -#define LPFC_DRB_RQ 4 +#define LPFC_DRB_EQ 1 +#define LPFC_DRB_CQ 2 +#define LPFC_DRB_MQ 3 +#define LPFC_DRB_WQ 4 +#define LPFC_DRB_RQ 5 -#define LPFC_DRB_MAX 4 +#define LPFC_DRB_MAX 5 #define IDIAG_DRBACC_REGID_INDX 0 #define IDIAG_DRBACC_VALUE_INDX 1 diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 234c7c015982..74895e62aaea 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1661,6 +1661,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, if (ndlp->nrport) { ndlp->nrport = NULL; lpfc_nlp_put(ndlp); + new_ndlp->nlp_fc4_type = ndlp->nlp_fc4_type; } /* We shall actually free the ndlp with both nlp_DID and @@ -2293,10 +2294,11 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->nvmet_support) { bf_set(prli_tgt, npr_nvme, 1); bf_set(prli_disc, npr_nvme, 1); - } else { bf_set(prli_init, npr_nvme, 1); + bf_set(prli_conf, npr_nvme, 1); } + npr_nvme->word1 = cpu_to_be32(npr_nvme->word1); npr_nvme->word4 = cpu_to_be32(npr_nvme->word4); elsiocb->iocb_flag |= LPFC_PRLI_NVME_REQ; @@ -5269,6 +5271,9 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) case LPFC_LINK_SPEED_32GHZ: rdp_speed = RDP_PS_32GB; break; + case LPFC_LINK_SPEED_64GHZ: + rdp_speed = RDP_PS_64GB; + break; default: rdp_speed = RDP_PS_UNKNOWN; break; @@ -5276,6 +5281,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) desc->info.port_speed.speed = cpu_to_be16(rdp_speed); + if (phba->lmt & LMT_64Gb) + rdp_cap |= RDP_PS_64GB; if (phba->lmt & LMT_32Gb) rdp_cap |= RDP_PS_32GB; if (phba->lmt & LMT_16Gb) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index b159a5c4e388..3e7712cd6c9a 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -696,8 +696,9 @@ lpfc_work_done(struct lpfc_hba *phba) phba->hba_flag & HBA_SP_QUEUE_EVT)) { if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); + /* Preserve legacy behavior. */ + if (!(phba->hba_flag & HBA_SP_QUEUE_EVT)) + set_bit(LPFC_DATA_READY, &phba->data_flags); } else { if (phba->link_state >= LPFC_LINK_UP || phba->link_flag & LS_MDS_LOOPBACK) { @@ -958,6 +959,7 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); if (!NLP_CHK_NODE_ACT(ndlp)) continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) @@ -3083,6 +3085,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) case LPFC_LINK_SPEED_10GHZ: case LPFC_LINK_SPEED_16GHZ: case LPFC_LINK_SPEED_32GHZ: + case LPFC_LINK_SPEED_64GHZ: break; default: phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN; @@ -3873,6 +3876,10 @@ int lpfc_issue_gidft(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) + ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); /* Good status, issue CT Request to NameServer */ if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index bdc1f184f67a..08a3f1520159 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1177,6 +1177,9 @@ struct fc_rdp_link_error_status_desc { #define RDP_PS_8GB 0x0800 #define RDP_PS_16GB 0x0400 #define RDP_PS_32GB 0x0200 +#define RDP_PS_64GB 0x0100 +#define RDP_PS_128GB 0x0080 +#define RDP_PS_256GB 0x0040 #define RDP_CAP_USER_CONFIGURED 0x0002 #define RDP_CAP_UNKNOWN 0x0001 @@ -1580,6 +1583,7 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_LANCER_FCOE 0xe260 #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268 #define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 +#define PCI_DEVICE_ID_LANCER_G7_FC 0xf400 #define PCI_DEVICE_ID_SAT_SMB 0xf011 #define PCI_DEVICE_ID_SAT_MID 0xf015 #define PCI_DEVICE_ID_RFLY 0xf095 @@ -2257,6 +2261,9 @@ typedef struct { #define LINK_SPEED_10G 0x10 /* 10 Gigabaud */ #define LINK_SPEED_16G 0x11 /* 16 Gigabaud */ #define LINK_SPEED_32G 0x14 /* 32 Gigabaud */ +#define LINK_SPEED_64G 0x17 /* 64 Gigabaud */ +#define LINK_SPEED_128G 0x1A /* 128 Gigabaud */ +#define LINK_SPEED_256G 0x1D /* 256 Gigabaud */ } INIT_LINK_VAR; @@ -2441,6 +2448,9 @@ typedef struct { #define LMT_10Gb 0x100 #define LMT_16Gb 0x200 #define LMT_32Gb 0x400 +#define LMT_64Gb 0x800 +#define LMT_128Gb 0x1000 +#define LMT_256Gb 0x2000 uint32_t rsvd2; uint32_t rsvd3; uint32_t max_xri; @@ -2965,6 +2975,9 @@ struct lpfc_mbx_read_top { #define LPFC_LINK_SPEED_10GHZ 0x40 #define LPFC_LINK_SPEED_16GHZ 0x80 #define LPFC_LINK_SPEED_32GHZ 0x90 +#define LPFC_LINK_SPEED_64GHZ 0xA0 +#define LPFC_LINK_SPEED_128GHZ 0xB0 +#define LPFC_LINK_SPEED_256GHZ 0xC0 }; /* Structure for MB Command CLEAR_LA (22) */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 73c2f6971d2b..98b80559c215 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -84,6 +84,7 @@ struct lpfc_sli_intf { #define LPFC_SLI_INTF_IF_TYPE_0 0 #define LPFC_SLI_INTF_IF_TYPE_1 1 #define LPFC_SLI_INTF_IF_TYPE_2 2 +#define LPFC_SLI_INTF_IF_TYPE_6 6 #define lpfc_sli_intf_sli_family_SHIFT 8 #define lpfc_sli_intf_sli_family_MASK 0x0000000F #define lpfc_sli_intf_sli_family_WORD word0 @@ -731,11 +732,13 @@ struct lpfc_register { * register sets depending on the UCNA Port's reported if_type * value. For UCNA ports running SLI4 and if_type 0, they reside in * BAR4. For UCNA ports running SLI4 and if_type 2, they reside in - * BAR0. The offsets are the same so the driver must account for - * any base address difference. + * BAR0. For FC ports running SLI4 and if_type 6, they reside in + * BAR2. The offsets and base address are different, so the driver + * has to compute the register addresses accordingly */ #define LPFC_ULP0_RQ_DOORBELL 0x00A0 #define LPFC_ULP1_RQ_DOORBELL 0x00C0 +#define LPFC_IF6_RQ_DOORBELL 0x0080 #define lpfc_rq_db_list_fm_num_posted_SHIFT 24 #define lpfc_rq_db_list_fm_num_posted_MASK 0x00FF #define lpfc_rq_db_list_fm_num_posted_WORD word0 @@ -770,6 +773,20 @@ struct lpfc_register { #define lpfc_wq_db_ring_fm_id_MASK 0xFFFF #define lpfc_wq_db_ring_fm_id_WORD word0 +#define LPFC_IF6_WQ_DOORBELL 0x0040 +#define lpfc_if6_wq_db_list_fm_num_posted_SHIFT 24 +#define lpfc_if6_wq_db_list_fm_num_posted_MASK 0x00FF +#define lpfc_if6_wq_db_list_fm_num_posted_WORD word0 +#define lpfc_if6_wq_db_list_fm_dpp_SHIFT 23 +#define lpfc_if6_wq_db_list_fm_dpp_MASK 0x0001 +#define lpfc_if6_wq_db_list_fm_dpp_WORD word0 +#define lpfc_if6_wq_db_list_fm_dpp_id_SHIFT 16 +#define lpfc_if6_wq_db_list_fm_dpp_id_MASK 0x001F +#define lpfc_if6_wq_db_list_fm_dpp_id_WORD word0 +#define lpfc_if6_wq_db_list_fm_id_SHIFT 0 +#define lpfc_if6_wq_db_list_fm_id_MASK 0xFFFF +#define lpfc_if6_wq_db_list_fm_id_WORD word0 + #define LPFC_EQCQ_DOORBELL 0x0120 #define lpfc_eqcq_doorbell_se_SHIFT 31 #define lpfc_eqcq_doorbell_se_MASK 0x0001 @@ -805,6 +822,38 @@ struct lpfc_register { #define LPFC_CQID_HI_FIELD_SHIFT 10 #define LPFC_EQID_HI_FIELD_SHIFT 9 +#define LPFC_IF6_CQ_DOORBELL 0x00C0 +#define lpfc_if6_cq_doorbell_se_SHIFT 31 +#define lpfc_if6_cq_doorbell_se_MASK 0x0001 +#define lpfc_if6_cq_doorbell_se_WORD word0 +#define LPFC_IF6_CQ_SOLICIT_ENABLE_OFF 0 +#define LPFC_IF6_CQ_SOLICIT_ENABLE_ON 1 +#define lpfc_if6_cq_doorbell_arm_SHIFT 29 +#define lpfc_if6_cq_doorbell_arm_MASK 0x0001 +#define lpfc_if6_cq_doorbell_arm_WORD word0 +#define lpfc_if6_cq_doorbell_num_released_SHIFT 16 +#define lpfc_if6_cq_doorbell_num_released_MASK 0x1FFF +#define lpfc_if6_cq_doorbell_num_released_WORD word0 +#define lpfc_if6_cq_doorbell_cqid_SHIFT 0 +#define lpfc_if6_cq_doorbell_cqid_MASK 0xFFFF +#define lpfc_if6_cq_doorbell_cqid_WORD word0 + +#define LPFC_IF6_EQ_DOORBELL 0x0120 +#define lpfc_if6_eq_doorbell_io_SHIFT 31 +#define lpfc_if6_eq_doorbell_io_MASK 0x0001 +#define lpfc_if6_eq_doorbell_io_WORD word0 +#define LPFC_IF6_EQ_INTR_OVERRIDE_OFF 0 +#define LPFC_IF6_EQ_INTR_OVERRIDE_ON 1 +#define lpfc_if6_eq_doorbell_arm_SHIFT 29 +#define lpfc_if6_eq_doorbell_arm_MASK 0x0001 +#define lpfc_if6_eq_doorbell_arm_WORD word0 +#define lpfc_if6_eq_doorbell_num_released_SHIFT 16 +#define lpfc_if6_eq_doorbell_num_released_MASK 0x1FFF +#define lpfc_if6_eq_doorbell_num_released_WORD word0 +#define lpfc_if6_eq_doorbell_eqid_SHIFT 0 +#define lpfc_if6_eq_doorbell_eqid_MASK 0x0FFF +#define lpfc_if6_eq_doorbell_eqid_WORD word0 + #define LPFC_BMBX 0x0160 #define lpfc_bmbx_addr_SHIFT 2 #define lpfc_bmbx_addr_MASK 0x3FFFFFFF @@ -817,6 +866,7 @@ struct lpfc_register { #define lpfc_bmbx_rdy_WORD word0 #define LPFC_MQ_DOORBELL 0x0140 +#define LPFC_IF6_MQ_DOORBELL 0x0160 #define lpfc_mq_doorbell_num_posted_SHIFT 16 #define lpfc_mq_doorbell_num_posted_MASK 0x3FFF #define lpfc_mq_doorbell_num_posted_WORD word0 @@ -990,6 +1040,9 @@ struct eq_context { #define lpfc_eq_context_valid_SHIFT 29 #define lpfc_eq_context_valid_MASK 0x00000001 #define lpfc_eq_context_valid_WORD word0 +#define lpfc_eq_context_autovalid_SHIFT 28 +#define lpfc_eq_context_autovalid_MASK 0x00000001 +#define lpfc_eq_context_autovalid_WORD word0 uint32_t word1; #define lpfc_eq_context_count_SHIFT 26 #define lpfc_eq_context_count_MASK 0x00000003 @@ -1123,6 +1176,9 @@ struct cq_context { #define LPFC_CQ_CNT_512 0x1 #define LPFC_CQ_CNT_1024 0x2 #define LPFC_CQ_CNT_WORD7 0x3 +#define lpfc_cq_context_autovalid_SHIFT 15 +#define lpfc_cq_context_autovalid_MASK 0x00000001 +#define lpfc_cq_context_autovalid_WORD word0 uint32_t word1; #define lpfc_cq_eq_id_SHIFT 22 /* Version 0 Only */ #define lpfc_cq_eq_id_MASK 0x000000FF @@ -1181,9 +1237,9 @@ struct lpfc_mbx_cq_create_set { #define lpfc_mbx_cq_create_set_cqe_size_SHIFT 25 #define lpfc_mbx_cq_create_set_cqe_size_MASK 0x00000003 #define lpfc_mbx_cq_create_set_cqe_size_WORD word1 -#define lpfc_mbx_cq_create_set_auto_SHIFT 15 -#define lpfc_mbx_cq_create_set_auto_MASK 0x0000001 -#define lpfc_mbx_cq_create_set_auto_WORD word1 +#define lpfc_mbx_cq_create_set_autovalid_SHIFT 15 +#define lpfc_mbx_cq_create_set_autovalid_MASK 0x0000001 +#define lpfc_mbx_cq_create_set_autovalid_WORD word1 #define lpfc_mbx_cq_create_set_nodelay_SHIFT 14 #define lpfc_mbx_cq_create_set_nodelay_MASK 0x00000001 #define lpfc_mbx_cq_create_set_nodelay_WORD word1 @@ -1322,6 +1378,15 @@ struct lpfc_mbx_wq_create { #define lpfc_mbx_wq_create_page_size_MASK 0x000000FF #define lpfc_mbx_wq_create_page_size_WORD word1 #define LPFC_WQ_PAGE_SIZE_4096 0x1 +#define lpfc_mbx_wq_create_dpp_req_SHIFT 15 +#define lpfc_mbx_wq_create_dpp_req_MASK 0x00000001 +#define lpfc_mbx_wq_create_dpp_req_WORD word1 +#define lpfc_mbx_wq_create_doe_SHIFT 14 +#define lpfc_mbx_wq_create_doe_MASK 0x00000001 +#define lpfc_mbx_wq_create_doe_WORD word1 +#define lpfc_mbx_wq_create_toe_SHIFT 13 +#define lpfc_mbx_wq_create_toe_MASK 0x00000001 +#define lpfc_mbx_wq_create_toe_WORD word1 #define lpfc_mbx_wq_create_wqe_size_SHIFT 8 #define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F #define lpfc_mbx_wq_create_wqe_size_WORD word1 @@ -1350,6 +1415,28 @@ struct lpfc_mbx_wq_create { #define lpfc_mbx_wq_create_db_format_MASK 0x0000FFFF #define lpfc_mbx_wq_create_db_format_WORD word2 } response; + struct { + uint32_t word0; +#define lpfc_mbx_wq_create_dpp_rsp_SHIFT 31 +#define lpfc_mbx_wq_create_dpp_rsp_MASK 0x00000001 +#define lpfc_mbx_wq_create_dpp_rsp_WORD word0 +#define lpfc_mbx_wq_create_v1_q_id_SHIFT 0 +#define lpfc_mbx_wq_create_v1_q_id_MASK 0x0000FFFF +#define lpfc_mbx_wq_create_v1_q_id_WORD word0 + uint32_t word1; +#define lpfc_mbx_wq_create_v1_bar_set_SHIFT 0 +#define lpfc_mbx_wq_create_v1_bar_set_MASK 0x0000000F +#define lpfc_mbx_wq_create_v1_bar_set_WORD word1 + uint32_t doorbell_offset; + uint32_t word3; +#define lpfc_mbx_wq_create_dpp_id_SHIFT 16 +#define lpfc_mbx_wq_create_dpp_id_MASK 0x0000001F +#define lpfc_mbx_wq_create_dpp_id_WORD word3 +#define lpfc_mbx_wq_create_dpp_bar_SHIFT 0 +#define lpfc_mbx_wq_create_dpp_bar_MASK 0x0000000F +#define lpfc_mbx_wq_create_dpp_bar_WORD word3 + uint32_t dpp_offset; + } response_1; } u; }; @@ -2154,6 +2241,7 @@ struct lpfc_mbx_redisc_fcf_tbl { * command. */ #define ADD_STATUS_OPERATION_ALREADY_ACTIVE 0x67 +#define ADD_STATUS_FW_NOT_SUPPORTED 0xEB struct lpfc_mbx_sli4_config { struct mbox_header header; @@ -2590,6 +2678,7 @@ struct lpfc_mbx_read_rev { #define lpfc_mbx_rd_rev_vpd_MASK 0x00000001 #define lpfc_mbx_rd_rev_vpd_WORD word1 uint32_t first_hw_rev; +#define LPFC_G7_ASIC_1 0xd uint32_t second_hw_rev; uint32_t word4_rsvd; uint32_t third_hw_rev; @@ -3207,11 +3296,20 @@ struct lpfc_sli4_parameters { #define cfg_sli_hint_2_MASK 0x0000001f #define cfg_sli_hint_2_WORD word1 uint32_t word2; +#define cfg_eqav_SHIFT 31 +#define cfg_eqav_MASK 0x00000001 +#define cfg_eqav_WORD word2 uint32_t word3; uint32_t word4; #define cfg_cqv_SHIFT 14 #define cfg_cqv_MASK 0x00000003 #define cfg_cqv_WORD word4 +#define cfg_cqpsize_SHIFT 16 +#define cfg_cqpsize_MASK 0x000000ff +#define cfg_cqpsize_WORD word4 +#define cfg_cqav_SHIFT 31 +#define cfg_cqav_MASK 0x00000001 +#define cfg_cqav_WORD word4 uint32_t word5; uint32_t word6; #define cfg_mqv_SHIFT 14 @@ -3290,6 +3388,9 @@ struct lpfc_sli4_parameters { #define cfg_eqdr_SHIFT 8 #define cfg_eqdr_MASK 0x00000001 #define cfg_eqdr_WORD word19 +#define cfg_nosr_SHIFT 9 +#define cfg_nosr_MASK 0x00000001 +#define cfg_nosr_WORD word19 #define LPFC_NODELAY_MAX_IO 32 }; @@ -3874,6 +3975,9 @@ struct lpfc_acqe_fc_la { #define LPFC_FC_LA_SPEED_10G 0xA #define LPFC_FC_LA_SPEED_16G 0x10 #define LPFC_FC_LA_SPEED_32G 0x20 +#define LPFC_FC_LA_SPEED_64G 0x21 +#define LPFC_FC_LA_SPEED_128G 0x22 +#define LPFC_FC_LA_SPEED_256G 0x23 #define lpfc_acqe_fc_la_topology_SHIFT 16 #define lpfc_acqe_fc_la_topology_MASK 0x000000FF #define lpfc_acqe_fc_la_topology_WORD word0 @@ -4079,6 +4183,7 @@ struct wqe_common { #define wqe_iod_SHIFT 13 #define wqe_iod_MASK 0x00000001 #define wqe_iod_WORD word10 +#define LPFC_WQE_IOD_NONE 0 #define LPFC_WQE_IOD_WRITE 0 #define LPFC_WQE_IOD_READ 1 #define wqe_dbde_SHIFT 14 @@ -4123,6 +4228,9 @@ struct wqe_common { #define wqe_irsp_SHIFT 4 #define wqe_irsp_MASK 0x00000001 #define wqe_irsp_WORD word11 +#define wqe_pbde_SHIFT 5 +#define wqe_pbde_MASK 0x00000001 +#define wqe_pbde_WORD word11 #define wqe_sup_SHIFT 6 #define wqe_sup_MASK 0x00000001 #define wqe_sup_WORD word11 @@ -4343,9 +4451,9 @@ struct lpfc_nvme_prli { #define prli_init_SHIFT 5 #define prli_init_MASK 0x00000001 #define prli_init_WORD word4 -#define prli_recov_SHIFT 8 -#define prli_recov_MASK 0x00000001 -#define prli_recov_WORD word4 +#define prli_conf_SHIFT 7 +#define prli_conf_MASK 0x00000001 +#define prli_conf_WORD word4 uint32_t word5; #define prli_fb_sz_SHIFT 0 #define prli_fb_sz_MASK 0x0000ffff @@ -4494,17 +4602,20 @@ union lpfc_wqe128 { struct fcp_icmnd64_wqe fcp_icmd; struct fcp_iread64_wqe fcp_iread; struct fcp_iwrite64_wqe fcp_iwrite; + struct abort_cmd_wqe abort_cmd; + struct create_xri_wqe create_xri; + struct xmit_bcast64_wqe xmit_bcast64; + struct xmit_seq64_wqe xmit_sequence; + struct xmit_bls_rsp64_wqe xmit_bls_rsp; + struct xmit_els_rsp64_wqe xmit_els_rsp; + struct els_request64_wqe els_req; + struct gen_req64_wqe gen_req; struct fcp_trsp64_wqe fcp_trsp; struct fcp_tsend64_wqe fcp_tsend; struct fcp_treceive64_wqe fcp_treceive; - struct xmit_seq64_wqe xmit_sequence; - struct gen_req64_wqe gen_req; + struct send_frame_wqe send_frame; }; -#define LPFC_GROUP_OJECT_MAGIC_G5 0xfeaa0001 -#define LPFC_GROUP_OJECT_MAGIC_G6 0xfeaa0003 -#define LPFC_FILE_TYPE_GROUP 0xf7 -#define LPFC_FILE_ID_GROUP 0xa2 struct lpfc_grp_hdr { uint32_t size; uint32_t magic_number; diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h index 0ba3733eb36d..07ee34017d88 100644 --- a/drivers/scsi/lpfc/lpfc_ids.h +++ b/drivers/scsi/lpfc/lpfc_ids.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -116,6 +116,8 @@ const struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7_FC, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f539c554588c..7887468c71b4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -731,7 +731,9 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) && - !(phba->lmt & LMT_32Gb))) { + !(phba->lmt & LMT_32Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) && + !(phba->lmt & LMT_64Gb))) { /* Reset link speed to auto */ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1302 Invalid speed for this board:%d " @@ -958,6 +960,7 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) struct lpfc_sli_ring *pring; LIST_HEAD(completions); int i; + struct lpfc_iocbq *piocb, *next_iocb; if (phba->sli_rev != LPFC_SLI_REV4) { for (i = 0; i < psli->num_rings; i++) { @@ -983,6 +986,9 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) if (!pring) continue; spin_lock_irq(&pring->ring_lock); + list_for_each_entry_safe(piocb, next_iocb, + &pring->txcmplq, list) + piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; list_splice_init(&pring->txcmplq, &completions); pring->txcmplq_cnt = 0; spin_unlock_irq(&pring->ring_lock); @@ -1757,7 +1763,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, int rc; uint32_t intr_mode; - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) { /* * On error status condition, driver need to wait for port @@ -1888,6 +1894,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) break; case LPFC_SLI_INTF_IF_TYPE_2: + case LPFC_SLI_INTF_IF_TYPE_6: pci_rd_rc1 = lpfc_readl( phba->sli4_hba.u.if_type2.STATUSregaddr, &portstat_reg.word0); @@ -2269,7 +2276,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) && descp && descp[0] != '\0') return; - if (phba->lmt & LMT_32Gb) + if (phba->lmt & LMT_64Gb) + max_speed = 64; + else if (phba->lmt & LMT_32Gb) max_speed = 32; else if (phba->lmt & LMT_16Gb) max_speed = 16; @@ -2468,6 +2477,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) case PCI_DEVICE_ID_LANCER_G6_FC: m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"}; break; + case PCI_DEVICE_ID_LANCER_G7_FC: + m = (typeof(m)){"LPe36000", "PCIe", "Fibre Channel Adapter"}; + break; case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; @@ -4104,6 +4116,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) sizeof fc_host_symbolic_name(shost)); fc_host_supported_speeds(shost) = 0; + if (phba->lmt & LMT_64Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_64GBIT; if (phba->lmt & LMT_32Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_32GBIT; if (phba->lmt & LMT_16Gb) @@ -4440,6 +4454,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, case LPFC_FC_LA_SPEED_32G: port_speed = 32000; break; + case LPFC_FC_LA_SPEED_64G: + port_speed = 64000; + break; default: port_speed = 0; } @@ -5895,7 +5912,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size * used to create the sg_dma_buf_pool must be calculated. */ - if (phba->cfg_enable_bg) { + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { /* * The scsi_buf for a T10-DIF I/O holds the FCP cmnd, * the FCP rsp, and a SGE. Sice we have no control @@ -6014,7 +6031,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) return -ENOMEM; /* IF Type 2 ports get initialized now. */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) { rc = lpfc_pci_function_reset(phba); if (unlikely(rc)) { @@ -7344,6 +7361,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) } break; case LPFC_SLI_INTF_IF_TYPE_2: + case LPFC_SLI_INTF_IF_TYPE_6: /* Final checks. The port status should be clean. */ if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, ®_data.word0) || @@ -7426,13 +7444,36 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type) phba->sli4_hba.WQDBregaddr = phba->sli4_hba.conf_regs_memmap_p + LPFC_ULP0_WQ_DOORBELL; - phba->sli4_hba.EQCQDBregaddr = + phba->sli4_hba.CQDBregaddr = phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL; + phba->sli4_hba.EQDBregaddr = phba->sli4_hba.CQDBregaddr; phba->sli4_hba.MQDBregaddr = phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL; phba->sli4_hba.BMBXregaddr = phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX; break; + case LPFC_SLI_INTF_IF_TYPE_6: + phba->sli4_hba.u.if_type2.EQDregaddr = + phba->sli4_hba.conf_regs_memmap_p + + LPFC_CTL_PORT_EQ_DELAY_OFFSET; + phba->sli4_hba.u.if_type2.ERR1regaddr = + phba->sli4_hba.conf_regs_memmap_p + + LPFC_CTL_PORT_ER1_OFFSET; + phba->sli4_hba.u.if_type2.ERR2regaddr = + phba->sli4_hba.conf_regs_memmap_p + + LPFC_CTL_PORT_ER2_OFFSET; + phba->sli4_hba.u.if_type2.CTRLregaddr = + phba->sli4_hba.conf_regs_memmap_p + + LPFC_CTL_PORT_CTL_OFFSET; + phba->sli4_hba.u.if_type2.STATUSregaddr = + phba->sli4_hba.conf_regs_memmap_p + + LPFC_CTL_PORT_STA_OFFSET; + phba->sli4_hba.PSMPHRregaddr = + phba->sli4_hba.conf_regs_memmap_p + + LPFC_CTL_PORT_SEM_OFFSET; + phba->sli4_hba.BMBXregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX; + break; case LPFC_SLI_INTF_IF_TYPE_1: default: dev_printk(KERN_ERR, &phba->pcidev->dev, @@ -7446,20 +7487,43 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type) * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map. * @phba: pointer to lpfc hba data structure. * - * This routine is invoked to set up SLI4 BAR1 control status register (CSR) - * memory map. + * This routine is invoked to set up SLI4 BAR1 register memory map. **/ static void -lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba) +lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba, uint32_t if_type) { - phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_SLIPORT_IF0_SMPHR; - phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_ISR0; - phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_IMR0; - phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_ISCR0; + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + phba->sli4_hba.PSMPHRregaddr = + phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_SLIPORT_IF0_SMPHR; + phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_ISR0; + phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_IMR0; + phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_ISCR0; + break; + case LPFC_SLI_INTF_IF_TYPE_6: + phba->sli4_hba.RQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p + + LPFC_IF6_RQ_DOORBELL; + phba->sli4_hba.WQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p + + LPFC_IF6_WQ_DOORBELL; + phba->sli4_hba.CQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p + + LPFC_IF6_CQ_DOORBELL; + phba->sli4_hba.EQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p + + LPFC_IF6_EQ_DOORBELL; + phba->sli4_hba.MQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p + + LPFC_IF6_MQ_DOORBELL; + break; + case LPFC_SLI_INTF_IF_TYPE_2: + case LPFC_SLI_INTF_IF_TYPE_1: + default: + dev_err(&phba->pcidev->dev, + "FATAL - unsupported SLI4 interface type - %d\n", + if_type); + break; + } } /** @@ -7484,8 +7548,10 @@ lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf) phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + vf * LPFC_VFR_PAGE_SIZE + LPFC_ULP0_WQ_DOORBELL); - phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + - vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL); + phba->sli4_hba.CQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + + vf * LPFC_VFR_PAGE_SIZE + + LPFC_EQCQ_DOORBELL); + phba->sli4_hba.EQDBregaddr = phba->sli4_hba.CQDBregaddr; phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL); phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p + @@ -7722,7 +7788,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) /* Update link speed if forced link speed is supported */ if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { forced_link_speed = bf_get(lpfc_mbx_rd_conf_link_speed, rd_config); if (forced_link_speed) { @@ -7757,6 +7823,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->cfg_link_speed = LPFC_USER_LINK_SPEED_32G; break; + case LINK_SPEED_64G: + phba->cfg_link_speed = + LPFC_USER_LINK_SPEED_64G; + break; case 0xffff: phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; @@ -7782,7 +7852,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->cfg_hba_queue_depth = length; } - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < LPFC_SLI_INTF_IF_TYPE_2) goto read_cfg_out; @@ -7896,6 +7966,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) } mempool_free(mboxq, phba->mbox_mem_pool); break; + case LPFC_SLI_INTF_IF_TYPE_6: case LPFC_SLI_INTF_IF_TYPE_2: case LPFC_SLI_INTF_IF_TYPE_1: default: @@ -7992,6 +8063,7 @@ lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx) wqidx); return 1; } + qdesc->qe_valid = 1; phba->sli4_hba.nvme_cq[wqidx] = qdesc; qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, @@ -8011,9 +8083,10 @@ static int lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) { struct lpfc_queue *qdesc; + uint32_t wqesize; /* Create Fast Path FCP CQs */ - if (phba->fcp_embed_io) + if (phba->enab_exp_wqcq_pages) /* Increase the CQ size when WQEs contain an embedded cdb */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, phba->sli4_hba.cq_esize, @@ -8028,18 +8101,22 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) "0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx); return 1; } + qdesc->qe_valid = 1; phba->sli4_hba.fcp_cq[wqidx] = qdesc; /* Create Fast Path FCP WQs */ - if (phba->fcp_embed_io) + if (phba->enab_exp_wqcq_pages) { /* Increase the WQ size when WQEs contain an embedded cdb */ + wqesize = (phba->fcp_embed_io) ? + LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize; qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, - LPFC_WQE128_SIZE, + wqesize, LPFC_WQE_EXP_COUNT); - else + } else qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount); + if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0503 Failed allocate fast-path FCP WQ (%d)\n", @@ -8218,6 +8295,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "0497 Failed allocate EQ (%d)\n", idx); goto out_error; } + qdesc->qe_valid = 1; phba->sli4_hba.hba_eq[idx] = qdesc; } @@ -8243,6 +8321,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "CQ Set (%d)\n", idx); goto out_error; } + qdesc->qe_valid = 1; phba->sli4_hba.nvmet_cqset[idx] = qdesc; } } @@ -8260,6 +8339,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "0500 Failed allocate slow-path mailbox CQ\n"); goto out_error; } + qdesc->qe_valid = 1; phba->sli4_hba.mbx_cq = qdesc; /* Create slow-path ELS Complete Queue */ @@ -8271,6 +8351,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "0501 Failed allocate slow-path ELS CQ\n"); goto out_error; } + qdesc->qe_valid = 1; phba->sli4_hba.els_cq = qdesc; @@ -8316,6 +8397,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "6079 Failed allocate NVME LS CQ\n"); goto out_error; } + qdesc->qe_valid = 1; phba->sli4_hba.nvmels_cq = qdesc; /* Create NVME LS Work Queue */ @@ -9303,6 +9385,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) } break; case LPFC_SLI_INTF_IF_TYPE_2: + case LPFC_SLI_INTF_IF_TYPE_6: wait: /* * Poll the Port Status Register and wait for RDY for @@ -9458,7 +9541,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) } else { phba->pci_bar0_map = pci_resource_start(pdev, 1); bar0map_len = pci_resource_len(pdev, 1); - if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { dev_printk(KERN_ERR, &pdev->dev, "FATAL - No BAR0 mapping for SLI4, if_type 2\n"); goto out; @@ -9495,13 +9578,32 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) } phba->pci_bar2_memmap_p = phba->sli4_hba.ctrl_regs_memmap_p; - lpfc_sli4_bar1_register_memmap(phba); + lpfc_sli4_bar1_register_memmap(phba, if_type); } else { error = -ENOMEM; goto out_iounmap_conf; } } + if ((if_type == LPFC_SLI_INTF_IF_TYPE_6) && + (pci_resource_start(pdev, PCI_64BIT_BAR2))) { + /* + * Map SLI4 if type 6 HBA Doorbell Register base to a kernel + * virtual address and setup the registers. + */ + phba->pci_bar1_map = pci_resource_start(pdev, PCI_64BIT_BAR2); + bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2); + phba->sli4_hba.drbl_regs_memmap_p = + ioremap(phba->pci_bar1_map, bar1map_len); + if (!phba->sli4_hba.drbl_regs_memmap_p) { + dev_err(&pdev->dev, + "ioremap failed for SLI4 HBA doorbell registers.\n"); + goto out_iounmap_conf; + } + phba->pci_bar2_memmap_p = phba->sli4_hba.drbl_regs_memmap_p; + lpfc_sli4_bar1_register_memmap(phba, if_type); + } + if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { if (pci_resource_start(pdev, PCI_64BIT_BAR4)) { /* @@ -9532,6 +9634,41 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) } } + if (if_type == LPFC_SLI_INTF_IF_TYPE_6 && + pci_resource_start(pdev, PCI_64BIT_BAR4)) { + /* + * Map SLI4 if type 6 HBA DPP Register base to a kernel + * virtual address and setup the registers. + */ + phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4); + bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4); + phba->sli4_hba.dpp_regs_memmap_p = + ioremap(phba->pci_bar2_map, bar2map_len); + if (!phba->sli4_hba.dpp_regs_memmap_p) { + dev_err(&pdev->dev, + "ioremap failed for SLI4 HBA dpp registers.\n"); + goto out_iounmap_ctrl; + } + phba->pci_bar4_memmap_p = phba->sli4_hba.dpp_regs_memmap_p; + } + + /* Set up the EQ/CQ register handeling functions now */ + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + case LPFC_SLI_INTF_IF_TYPE_2: + phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_eq_clr_intr; + phba->sli4_hba.sli4_eq_release = lpfc_sli4_eq_release; + phba->sli4_hba.sli4_cq_release = lpfc_sli4_cq_release; + break; + case LPFC_SLI_INTF_IF_TYPE_6: + phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_if6_eq_clr_intr; + phba->sli4_hba.sli4_eq_release = lpfc_sli4_if6_eq_release; + phba->sli4_hba.sli4_cq_release = lpfc_sli4_if6_cq_release; + break; + default: + break; + } + return 0; out_iounmap_all: @@ -9566,6 +9703,10 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) case LPFC_SLI_INTF_IF_TYPE_2: iounmap(phba->sli4_hba.conf_regs_memmap_p); break; + case LPFC_SLI_INTF_IF_TYPE_6: + iounmap(phba->sli4_hba.drbl_regs_memmap_p); + iounmap(phba->sli4_hba.conf_regs_memmap_p); + break; case LPFC_SLI_INTF_IF_TYPE_1: default: dev_printk(KERN_ERR, &phba->pcidev->dev, @@ -10435,6 +10576,8 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters); sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters); sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters); + sli4_params->eqav = bf_get(cfg_eqav, mbx_sli4_parameters); + sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters); sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters); sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt, mbx_sli4_parameters); @@ -10465,8 +10608,32 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; } - if (bf_get(cfg_xib, mbx_sli4_parameters) && phba->cfg_suppress_rsp) + /* Only embed PBDE for if_type 6 */ + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_6) { + phba->fcp_embed_pbde = 1; + phba->nvme_embed_pbde = 1; + } + + /* PBDE support requires xib be set */ + if (!bf_get(cfg_xib, mbx_sli4_parameters)) { + phba->fcp_embed_pbde = 0; + phba->nvme_embed_pbde = 0; + } + + /* + * To support Suppress Response feature we must satisfy 3 conditions. + * lpfc_suppress_rsp module parameter must be set (default). + * In SLI4-Parameters Descriptor: + * Extended Inline Buffers (XIB) must be supported. + * Suppress Response IU Not Supported (SRIUNS) must NOT be supported + * (double negative). + */ + if (phba->cfg_suppress_rsp && bf_get(cfg_xib, mbx_sli4_parameters) && + !(bf_get(cfg_nosr, mbx_sli4_parameters))) phba->sli.sli_flag |= LPFC_SLI_SUPPRESS_RSP; + else + phba->cfg_suppress_rsp = 0; if (bf_get(cfg_eqdr, mbx_sli4_parameters)) phba->sli.sli_flag |= LPFC_SLI_USE_EQDR; @@ -10476,15 +10643,28 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE; /* - * Issue IOs with CDB embedded in WQE to minimized the number - * of DMAs the firmware has to do. Setting this to 1 also forces - * the driver to use 128 bytes WQEs for FCP IOs. + * Check whether the adapter supports an embedded copy of the + * FCP CMD IU within the WQE for FCP_Ixxx commands. In order + * to use this option, 128-byte WQEs must be used. */ if (bf_get(cfg_ext_embed_cb, mbx_sli4_parameters)) phba->fcp_embed_io = 1; else phba->fcp_embed_io = 0; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME, + "6422 XIB %d: FCP %d %d NVME %d %d %d %d\n", + bf_get(cfg_xib, mbx_sli4_parameters), + phba->fcp_embed_pbde, phba->fcp_embed_io, + phba->nvme_support, phba->nvme_embed_pbde, + phba->cfg_nvme_embed_cmd, phba->cfg_suppress_rsp); + + if ((bf_get(cfg_cqpsize, mbx_sli4_parameters) & LPFC_CQ_16K_PAGE_SZ) && + (bf_get(cfg_wqpsize, mbx_sli4_parameters) & LPFC_WQ_16K_PAGE_SZ) && + (sli4_params->wqsize & LPFC_WQ_SZ128_SUPPORT)) + phba->enab_exp_wqcq_pages = 1; + else + phba->enab_exp_wqcq_pages = 0; /* * Check if the SLI port supports MDS Diagnostics */ @@ -11137,6 +11317,27 @@ lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba) } +static void +lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, + uint32_t magic_number, uint32_t ftype, uint32_t fid, uint32_t fsize, + const struct firmware *fw) +{ + if (offset == ADD_STATUS_FW_NOT_SUPPORTED) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3030 This firmware version is not supported on " + "this HBA model. Device:%x Magic:%x Type:%x " + "ID:%x Size %d %zd\n", + phba->pcidev->device, magic_number, ftype, fid, + fsize, fw->size); + else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3022 FW Download failed. Device:%x Magic:%x Type:%x " + "ID:%x Size %d %zd\n", + phba->pcidev->device, magic_number, ftype, fid, + fsize, fw->size); +} + + /** * lpfc_write_firmware - attempt to write a firmware image to the port * @fw: pointer to firmware image returned from request_firmware. @@ -11164,20 +11365,10 @@ lpfc_write_firmware(const struct firmware *fw, void *context) magic_number = be32_to_cpu(image->magic_number); ftype = bf_get_be32(lpfc_grp_hdr_file_type, image); - fid = bf_get_be32(lpfc_grp_hdr_id, image), + fid = bf_get_be32(lpfc_grp_hdr_id, image); fsize = be32_to_cpu(image->size); INIT_LIST_HEAD(&dma_buffer_list); - if ((magic_number != LPFC_GROUP_OJECT_MAGIC_G5 && - magic_number != LPFC_GROUP_OJECT_MAGIC_G6) || - ftype != LPFC_FILE_TYPE_GROUP || fsize != fw->size) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3022 Invalid FW image found. " - "Magic:%x Type:%x ID:%x Size %d %zd\n", - magic_number, ftype, fid, fsize, fw->size); - rc = -EINVAL; - goto release_out; - } lpfc_decode_firmware_rev(phba, fwrev, 1); if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -11218,11 +11409,18 @@ lpfc_write_firmware(const struct firmware *fw, void *context) } rc = lpfc_wr_object(phba, &dma_buffer_list, (fw->size - offset), &offset); - if (rc) + if (rc) { + lpfc_log_write_firmware_error(phba, offset, + magic_number, ftype, fid, fsize, fw); goto release_out; + } } rc = offset; - } + } else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3029 Skipped Firmware update, Current " + "Version:%s New Version:%s\n", + fwrev, image->revision); release_out: list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) { @@ -11253,7 +11451,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) const struct firmware *fw; /* Only supported on SLI4 interface type 2 for now */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < LPFC_SLI_INTF_IF_TYPE_2) return -EPERM; @@ -11493,13 +11691,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) /* Remove FC host and then SCSI host with the physical port */ fc_remove_host(shost); scsi_remove_host(shost); - /* - * Bring down the SLI Layer. This step disables all interrupts, - * clears the rings, discards all mailbox commands, and resets - * the HBA FCoE function. - */ - lpfc_debugfs_terminate(vport); - lpfc_sli4_hba_unset(phba); /* Perform ndlp cleanup on the physical port. The nvme and nvmet * localports are destroyed after to cleanup all transport memory. @@ -11508,6 +11699,13 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) lpfc_nvmet_destroy_targetport(phba); lpfc_nvme_destroy_localport(vport); + /* + * Bring down the SLI Layer. This step disables all interrupts, + * clears the rings, discards all mailbox commands, and resets + * the HBA FCoE function. + */ + lpfc_debugfs_terminate(vport); + lpfc_sli4_hba_unset(phba); lpfc_stop_hba_timers(phba); spin_lock_irq(&phba->hbalock); @@ -12227,6 +12425,7 @@ int lpfc_fof_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; + uint32_t wqesize; /* Create FOF EQ */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, @@ -12235,12 +12434,13 @@ lpfc_fof_queue_create(struct lpfc_hba *phba) if (!qdesc) goto out_error; + qdesc->qe_valid = 1; phba->sli4_hba.fof_eq = qdesc; if (phba->cfg_fof) { /* Create OAS CQ */ - if (phba->fcp_embed_io) + if (phba->enab_exp_wqcq_pages) qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, phba->sli4_hba.cq_esize, @@ -12253,19 +12453,23 @@ lpfc_fof_queue_create(struct lpfc_hba *phba) if (!qdesc) goto out_error; + qdesc->qe_valid = 1; phba->sli4_hba.oas_cq = qdesc; /* Create OAS WQ */ - if (phba->fcp_embed_io) + if (phba->enab_exp_wqcq_pages) { + wqesize = (phba->fcp_embed_io) ? + LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize; qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, - LPFC_WQE128_SIZE, + wqesize, LPFC_WQE_EXP_COUNT); - else + } else qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount); + if (!qdesc) goto out_error; @@ -12379,6 +12583,8 @@ lpfc_init(void) fc_release_transport(lpfc_transport_template); return -ENOMEM; } + lpfc_nvme_cmd_template(); + lpfc_nvmet_cmd_template(); /* Initialize in case vector mapping is needed */ lpfc_used_cpu = NULL; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 81fb92967b11..47c02da11f01 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -557,6 +557,10 @@ lpfc_init_link(struct lpfc_hba * phba, mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; mb->un.varInitLnk.link_speed = LINK_SPEED_32G; break; + case LPFC_USER_LINK_SPEED_64G: + mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; + mb->un.varInitLnk.link_speed = LINK_SPEED_64G; + break; case LPFC_USER_LINK_SPEED_AUTO: default: mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; @@ -2170,10 +2174,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) /* Only FC supports upd bit */ if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) && (vport->fc_flag & FC_VFI_REGISTERED) && - (!phba->fc_topology_changed)) { - bf_set(lpfc_reg_vfi_vp, reg_vfi, 0); + (!phba->fc_topology_changed)) bf_set(lpfc_reg_vfi_upd, reg_vfi, 1); - } bf_set(lpfc_reg_vfi_bbcr, reg_vfi, 0); bf_set(lpfc_reg_vfi_bbscn, reg_vfi, 0); diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 87c08ff37ddd..41361662ff08 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -753,12 +753,16 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys); rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe); if (rc < 0) { + (rqbp->rqb_free_buffer)(phba, rqb_entry); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6409 Cannot post to RQ %d: %x %x\n", + "6409 Cannot post to HRQ %d: %x %x %x " + "DRQ %x %x\n", rqb_entry->hrq->queue_id, rqb_entry->hrq->host_index, - rqb_entry->hrq->hba_index); - (rqbp->rqb_free_buffer)(phba, rqb_entry); + rqb_entry->hrq->hba_index, + rqb_entry->hrq->entry_count, + rqb_entry->drq->host_index, + rqb_entry->drq->hba_index); } else { list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list); rqbp->buffer_count++; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d841aa42f607..022060636ae1 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ - /******************************************************************* +/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1998,8 +1998,14 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type |= NLP_NVME_TARGET; if (bf_get_be32(prli_disc, nvpr)) ndlp->nlp_type |= NLP_NVME_DISCOVERY; + + /* + * If prli_fba is set, the Target supports FirstBurst. + * If prli_fb_sz is 0, the FirstBurst size is unlimited, + * otherwise it defines the actual size supported by + * the NVME Target. + */ if ((bf_get_be32(prli_fba, nvpr) == 1) && - (bf_get_be32(prli_fb_sz, nvpr) > 0) && (phba->cfg_nvme_enable_fb) && (!phba->nvmet_support)) { /* Both sides support FB. The target's first @@ -2008,12 +2014,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_flag |= NLP_FIRSTBURST; ndlp->nvme_fb_size = bf_get_be32(prli_fb_sz, nvpr); + + /* Expressed in units of 512 bytes */ + if (ndlp->nvme_fb_size) + ndlp->nvme_fb_size <<= + LPFC_NVME_FB_SHIFT; + else + ndlp->nvme_fb_size = LPFC_NVME_MAX_FB; } } - if (bf_get_be32(prli_recov, nvpr)) - ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; - lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6029 NVME PRLI Cmpl w1 x%08x " "w4 x%08x w5 x%08x flag x%x, " diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 81e3a4f10c3c..378dca40ca20 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -65,6 +65,136 @@ lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_nvme_buf *); static struct nvme_fc_port_template lpfc_nvme_template; +static union lpfc_wqe128 lpfc_iread_cmd_template; +static union lpfc_wqe128 lpfc_iwrite_cmd_template; +static union lpfc_wqe128 lpfc_icmnd_cmd_template; + +/* Setup WQE templates for NVME IOs */ +void +lpfc_nvme_cmd_template(void) +{ + union lpfc_wqe128 *wqe; + + /* IREAD template */ + wqe = &lpfc_iread_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE); + bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_nvme, &wqe->fcp_iread.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, NVME_READ_CMD); + bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* IWRITE template */ + wqe = &lpfc_iwrite_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - initial_xfer_len is variable */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE); + bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_nvme, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); + bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, NVME_WRITE_CMD); + bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* ICMND template */ + wqe = &lpfc_icmnd_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - payload_offset_len is variable */ + + /* Word 4, 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE); + bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE); + bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); + + /* Word 11 */ + bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, FCP_COMMAND); + bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); + + /* Word 12, 13, 14, 15 - is zero */ +} + /** * lpfc_nvme_create_queue - * @lpfc_pnvme: Pointer to the driver's nvme instance data @@ -241,10 +371,11 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, ndlp = (struct lpfc_nodelist *)cmdwqe->context1; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6047 nvme cmpl Enter " - "Data %p DID %x Xri: %x status %x cmd:%p lsreg:%p " - "bmp:%p ndlp:%p\n", + "Data %p DID %x Xri: %x status %x reason x%x cmd:%p " + "lsreg:%p bmp:%p ndlp:%p\n", pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, cmdwqe->sli4_xritag, status, + (wcqe->parameter & 0xffff), cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp); lpfc_nvmeio_data(phba, "NVME LS CMPL: xri x%x stat x%x parm x%x\n", @@ -274,14 +405,14 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, static int lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, struct lpfc_dmabuf *inp, - struct nvmefc_ls_req *pnvme_lsreq, - void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_wcqe_complete *), - struct lpfc_nodelist *ndlp, uint32_t num_entry, - uint32_t tmo, uint8_t retry) + struct nvmefc_ls_req *pnvme_lsreq, + void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, + struct lpfc_wcqe_complete *), + struct lpfc_nodelist *ndlp, uint32_t num_entry, + uint32_t tmo, uint8_t retry) { - struct lpfc_hba *phba = vport->phba; - union lpfc_wqe *wqe; + struct lpfc_hba *phba = vport->phba; + union lpfc_wqe128 *wqe; struct lpfc_iocbq *genwqe; struct ulp_bde64 *bpl; struct ulp_bde64 bde; @@ -419,6 +550,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, { int ret = 0; struct lpfc_nvme_lport *lport; + struct lpfc_nvme_rport *rport; struct lpfc_vport *vport; struct lpfc_nodelist *ndlp; struct ulp_bde64 *bpl; @@ -437,19 +569,18 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, */ lport = (struct lpfc_nvme_lport *)pnvme_lport->private; + rport = (struct lpfc_nvme_rport *)pnvme_rport->private; vport = lport->vport; if (vport->load_flag & FC_UNLOADING) return -ENODEV; - if (vport->load_flag & FC_UNLOADING) - return -ENODEV; - - ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); + /* Need the ndlp. It is stored in the driver's rport. */ + ndlp = rport->ndlp; if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, - "6051 DID x%06x not an active rport.\n", - pnvme_rport->port_id); + "6051 Remoteport %p, rport has invalid ndlp. " + "Failing LS Req\n", pnvme_rport); return -ENODEV; } @@ -500,8 +631,9 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, /* Expand print to include key fields. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6149 ENTER. lport %p, rport %p lsreq%p rqstlen:%d " - "rsplen:%d %pad %pad\n", + "6149 Issue LS Req to DID 0x%06x lport %p, rport %p " + "lsreq%p rqstlen:%d rsplen:%d %pad %pad\n", + ndlp->nlp_DID, pnvme_lport, pnvme_rport, pnvme_lsreq, pnvme_lsreq->rqstlen, pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, @@ -517,7 +649,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, ndlp, 2, 30, 0); if (ret != WQE_SUCCESS) { atomic_inc(&lport->xmt_ls_err); - lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, "6052 EXIT. issue ls wqe failed lport %p, " "rport %p lsreq%p Status %x DID %x\n", pnvme_lport, pnvme_rport, pnvme_lsreq, @@ -610,16 +742,25 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, } /* Fix up the existing sgls for NVME IO. */ -static void +static inline void lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport, struct lpfc_nvme_buf *lpfc_ncmd, struct nvmefc_fcp_req *nCmd) { + struct lpfc_hba *phba = vport->phba; struct sli4_sge *sgl; union lpfc_wqe128 *wqe; uint32_t *wptr, *dptr; /* + * Get a local pointer to the built-in wqe and correct + * the cmd size to match NVME's 96 bytes and fix + * the dma address. + */ + + wqe = &lpfc_ncmd->cur_iocbq.wqe; + + /* * Adjust the FCP_CMD and FCP_RSP DMA data and sge_len to * match NVME. NVME sends 96 bytes. Also, use the * nvme commands command and response dma addresses @@ -628,6 +769,60 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport, */ sgl = lpfc_ncmd->nvme_sgl; sgl->sge_len = cpu_to_le32(nCmd->cmdlen); + if (phba->cfg_nvme_embed_cmd) { + sgl->addr_hi = 0; + sgl->addr_lo = 0; + + /* Word 0-2 - NVME CMND IU (embedded payload) */ + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED; + wqe->generic.bde.tus.f.bdeSize = 56; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 64; /* Word 16 */ + + /* Word 10 - dbde is 0, wqes is 1 in template */ + + /* + * Embed the payload in the last half of the WQE + * WQE words 16-30 get the NVME CMD IU payload + * + * WQE words 16-19 get payload Words 1-4 + * WQE words 20-21 get payload Words 6-7 + * WQE words 22-29 get payload Words 16-23 + */ + wptr = &wqe->words[16]; /* WQE ptr */ + dptr = (uint32_t *)nCmd->cmdaddr; /* payload ptr */ + dptr++; /* Skip Word 0 in payload */ + + *wptr++ = *dptr++; /* Word 1 */ + *wptr++ = *dptr++; /* Word 2 */ + *wptr++ = *dptr++; /* Word 3 */ + *wptr++ = *dptr++; /* Word 4 */ + dptr++; /* Skip Word 5 in payload */ + *wptr++ = *dptr++; /* Word 6 */ + *wptr++ = *dptr++; /* Word 7 */ + dptr += 8; /* Skip Words 8-15 in payload */ + *wptr++ = *dptr++; /* Word 16 */ + *wptr++ = *dptr++; /* Word 17 */ + *wptr++ = *dptr++; /* Word 18 */ + *wptr++ = *dptr++; /* Word 19 */ + *wptr++ = *dptr++; /* Word 20 */ + *wptr++ = *dptr++; /* Word 21 */ + *wptr++ = *dptr++; /* Word 22 */ + *wptr = *dptr; /* Word 23 */ + } else { + sgl->addr_hi = cpu_to_le32(putPaddrHigh(nCmd->cmddma)); + sgl->addr_lo = cpu_to_le32(putPaddrLow(nCmd->cmddma)); + + /* Word 0-2 - NVME CMND IU Inline BDE */ + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + wqe->generic.bde.tus.f.bdeSize = nCmd->cmdlen; + wqe->generic.bde.addrHigh = sgl->addr_hi; + wqe->generic.bde.addrLow = sgl->addr_lo; + + /* Word 10 */ + bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); + bf_set(wqe_wqes, &wqe->generic.wqe_com, 0); + } sgl++; @@ -641,58 +836,6 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport, bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(nCmd->rsplen); - - /* - * Get a local pointer to the built-in wqe and correct - * the cmd size to match NVME's 96 bytes and fix - * the dma address. - */ - - /* 128 byte wqe support here */ - wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe; - - /* Word 0-2 - NVME CMND IU (embedded payload) */ - wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED; - wqe->generic.bde.tus.f.bdeSize = 60; - wqe->generic.bde.addrHigh = 0; - wqe->generic.bde.addrLow = 64; /* Word 16 */ - - /* Word 3 */ - bf_set(payload_offset_len, &wqe->fcp_icmd, - (nCmd->rsplen + nCmd->cmdlen)); - - /* Word 10 */ - bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); - - /* - * Embed the payload in the last half of the WQE - * WQE words 16-30 get the NVME CMD IU payload - * - * WQE words 16-19 get payload Words 1-4 - * WQE words 20-21 get payload Words 6-7 - * WQE words 22-29 get payload Words 16-23 - */ - wptr = &wqe->words[16]; /* WQE ptr */ - dptr = (uint32_t *)nCmd->cmdaddr; /* payload ptr */ - dptr++; /* Skip Word 0 in payload */ - - *wptr++ = *dptr++; /* Word 1 */ - *wptr++ = *dptr++; /* Word 2 */ - *wptr++ = *dptr++; /* Word 3 */ - *wptr++ = *dptr++; /* Word 4 */ - dptr++; /* Skip Word 5 in payload */ - *wptr++ = *dptr++; /* Word 6 */ - *wptr++ = *dptr++; /* Word 7 */ - dptr += 8; /* Skip Words 8-15 in payload */ - *wptr++ = *dptr++; /* Word 16 */ - *wptr++ = *dptr++; /* Word 17 */ - *wptr++ = *dptr++; /* Word 18 */ - *wptr++ = *dptr++; /* Word 19 */ - *wptr++ = *dptr++; /* Word 20 */ - *wptr++ = *dptr++; /* Word 21 */ - *wptr++ = *dptr++; /* Word 22 */ - *wptr = *dptr; /* Word 23 */ } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -980,14 +1123,14 @@ out_err: phba->cpucheck_cmpl_io[lpfc_ncmd->cpu]++; } #endif - freqpriv = nCmd->private; - freqpriv->nvme_buf = NULL; /* NVME targets need completion held off until the abort exchange * completes unless the NVME Rport is getting unregistered. */ if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) { + freqpriv = nCmd->private; + freqpriv->nvme_buf = NULL; nCmd->done(nCmd); lpfc_ncmd->nvmeCmd = NULL; } @@ -1025,7 +1168,7 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, struct lpfc_hba *phba = vport->phba; struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd; struct lpfc_iocbq *pwqeq = &(lpfc_ncmd->cur_iocbq); - union lpfc_wqe128 *wqe = (union lpfc_wqe128 *)&pwqeq->wqe; + union lpfc_wqe128 *wqe = &pwqeq->wqe; uint32_t req_len; if (!pnode || !NLP_CHK_NODE_ACT(pnode)) @@ -1035,9 +1178,16 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, * There are three possibilities here - use scatter-gather segment, use * the single mapping, or neither. */ - wqe->fcp_iwrite.initial_xfer_len = 0; if (nCmd->sg_cnt) { if (nCmd->io_dir == NVMEFC_FCP_WRITE) { + /* From the iwrite template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_iwrite_cmd_template.words[7], + sizeof(uint32_t) * 5); + + /* Word 4 */ + wqe->fcp_iwrite.total_xfer_len = nCmd->payload_length; + /* Word 5 */ if ((phba->cfg_nvme_enable_fb) && (pnode->nlp_flag & NLP_FIRSTBURST)) { @@ -1048,69 +1198,28 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, else wqe->fcp_iwrite.initial_xfer_len = pnode->nvme_fb_size; + } else { + wqe->fcp_iwrite.initial_xfer_len = 0; } - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->generic.wqe_com, - CMD_FCP_IWRITE64_WQE); - bf_set(wqe_pu, &wqe->generic.wqe_com, - PARM_READ_CHECK); - - /* Word 10 */ - bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, - LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, - LPFC_WQE_LENLOC_WORD4); - if (phba->cfg_nvme_oas) - bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1); - - /* Word 11 */ - bf_set(wqe_cmd_type, &wqe->generic.wqe_com, - NVME_WRITE_CMD); - atomic_inc(&phba->fc4NvmeOutputRequests); } else { - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->generic.wqe_com, - CMD_FCP_IREAD64_WQE); - bf_set(wqe_pu, &wqe->generic.wqe_com, - PARM_READ_CHECK); - - /* Word 10 */ - bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, - LPFC_WQE_IOD_READ); - bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, - LPFC_WQE_LENLOC_WORD4); - if (phba->cfg_nvme_oas) - bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1); - - /* Word 11 */ - bf_set(wqe_cmd_type, &wqe->generic.wqe_com, - NVME_READ_CMD); + /* From the iread template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_iread_cmd_template.words[7], + sizeof(uint32_t) * 5); + + /* Word 4 */ + wqe->fcp_iread.total_xfer_len = nCmd->payload_length; + + /* Word 5 */ + wqe->fcp_iread.rsrvd5 = 0; atomic_inc(&phba->fc4NvmeInputRequests); } } else { - /* Word 4 */ - wqe->fcp_icmd.rsrvd4 = 0; - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->generic.wqe_com, CMD_FCP_ICMND64_WQE); - bf_set(wqe_pu, &wqe->generic.wqe_com, 0); - - /* Word 10 */ - bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, - LPFC_WQE_LENLOC_NONE); - if (phba->cfg_nvme_oas) - bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1); - - /* Word 11 */ - bf_set(wqe_cmd_type, &wqe->generic.wqe_com, NVME_READ_CMD); - + /* From the icmnd template, initialize words 4 - 11 */ + memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4], + sizeof(uint32_t) * 8); atomic_inc(&phba->fc4NvmeControlRequests); } /* @@ -1118,25 +1227,21 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, * of the nvme_cmnd request_buffer */ + /* Word 3 */ + bf_set(payload_offset_len, &wqe->fcp_icmd, + (nCmd->rsplen + nCmd->cmdlen)); + /* Word 6 */ bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, phba->sli4_hba.rpi_ids[pnode->nlp_rpi]); bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag); - /* Word 7 */ - /* Preserve Class data in the ndlp. */ - bf_set(wqe_class, &wqe->generic.wqe_com, - (pnode->nlp_fcp_info & 0x0f)); - /* Word 8 */ wqe->generic.wqe_com.abort_tag = pwqeq->iotag; /* Word 9 */ bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag); - /* Word 11 */ - bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - pwqeq->vport = vport; return 0; } @@ -1164,10 +1269,11 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, { struct lpfc_hba *phba = vport->phba; struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd; - union lpfc_wqe128 *wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe; + union lpfc_wqe128 *wqe = &lpfc_ncmd->cur_iocbq.wqe; struct sli4_sge *sgl = lpfc_ncmd->nvme_sgl; struct scatterlist *data_sg; struct sli4_sge *first_data_sgl; + struct ulp_bde64 *bde; dma_addr_t physaddr; uint32_t num_bde = 0; uint32_t dma_len; @@ -1235,7 +1341,26 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, data_sg = sg_next(data_sg); sgl++; } + if (phba->nvme_embed_pbde) { + /* Use PBDE support for first SGL only, offset == 0 */ + /* Words 13-15 */ + bde = (struct ulp_bde64 *) + &wqe->words[13]; + bde->addrLow = first_data_sgl->addr_lo; + bde->addrHigh = first_data_sgl->addr_hi; + bde->tus.f.bdeSize = + le32_to_cpu(first_data_sgl->sge_len); + bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bde->tus.w = cpu_to_le32(bde->tus.w); + /* wqe_pbde is 1 in template */ + } else { + memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); + bf_set(wqe_pbde, &wqe->generic.wqe_com, 0); + } } else { + bf_set(wqe_pbde, &wqe->generic.wqe_com, 0); + memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); + /* For this clause to be valid, the payload_length * and sg_cnt must zero. */ @@ -1247,12 +1372,6 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, return 1; } } - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of WQE here - */ - wqe->fcp_iread.total_xfer_len = nCmd->payload_length; return 0; } @@ -1554,7 +1673,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_iocbq *abts_buf; struct lpfc_iocbq *nvmereq_wqe; struct lpfc_nvme_fcpreq_priv *freqpriv; - union lpfc_wqe *abts_wqe; + union lpfc_wqe128 *abts_wqe; unsigned long flags; int ret_val; @@ -2098,7 +2217,7 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc) break; } pwqeq = &(lpfc_ncmd->cur_iocbq); - wqe = (union lpfc_wqe128 *)&pwqeq->wqe; + wqe = &pwqeq->wqe; /* Allocate iotag for lpfc_ncmd->cur_iocbq. */ iotag = lpfc_sli_next_iotag(phba, pwqeq); @@ -2135,14 +2254,8 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc) lpfc_ncmd->cur_iocbq.context1 = lpfc_ncmd; - /* Word 7 */ - bf_set(wqe_erp, &wqe->generic.wqe_com, 0); - /* NVME upper layers will time things out, if needed */ - bf_set(wqe_tmo, &wqe->generic.wqe_com, 0); - - /* Word 10 */ - bf_set(wqe_ebde_cnt, &wqe->generic.wqe_com, 0); - bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); + /* Initialize WQE */ + memset(wqe, 0, sizeof(union lpfc_wqe)); /* add the nvme buffer to a post list */ list_add_tail(&lpfc_ncmd->list, &post_nblist); diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index e79f8f75758c..9216653e0441 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -27,6 +27,8 @@ #define LPFC_NVME_WAIT_TMO 10 #define LPFC_NVME_EXPEDITE_XRICNT 8 +#define LPFC_NVME_FB_SHIFT 9 +#define LPFC_NVME_MAX_FB (1 << 20) /* 1M */ struct lpfc_nvme_qhandle { uint32_t index; /* WQ index to use */ diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 8dbf5c9d51aa..7271c9d885dd 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channsel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -36,7 +36,7 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <../drivers/nvme/host/nvme.h> +#include <linux/nvme.h> #include <linux/nvme-fc-driver.h> #include <linux/nvme-fc.h> @@ -71,6 +71,151 @@ static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *, static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *, struct lpfc_nvmet_rcv_ctx *, uint32_t, uint16_t); +static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_nvmet_rcv_ctx *); + +static union lpfc_wqe128 lpfc_tsend_cmd_template; +static union lpfc_wqe128 lpfc_treceive_cmd_template; +static union lpfc_wqe128 lpfc_trsp_cmd_template; + +/* Setup WQE templates for NVME IOs */ +void +lpfc_nvmet_cmd_template(void) +{ + union lpfc_wqe128 *wqe; + + /* TSEND template */ + wqe = &lpfc_tsend_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - payload_offset_len is zero */ + + /* Word 4 - relative_offset is variable */ + + /* Word 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 - wqe_ar is variable */ + bf_set(wqe_cmnd, &wqe->fcp_tsend.wqe_com, CMD_FCP_TSEND64_WQE); + bf_set(wqe_pu, &wqe->fcp_tsend.wqe_com, PARM_REL_OFF); + bf_set(wqe_class, &wqe->fcp_tsend.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_tsend.wqe_com, SLI4_CT_RPI); + bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag, rcvoxid is variable */ + + /* Word 10 - wqes, xc is variable */ + bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0); + bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_tsend.wqe_com, LPFC_WQE_IOD_WRITE); + bf_set(wqe_lenloc, &wqe->fcp_tsend.wqe_com, LPFC_WQE_LENLOC_WORD12); + + /* Word 11 - sup, irsp, irsplen is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_tsend.wqe_com, FCP_COMMAND_TSEND); + bf_set(wqe_cqid, &wqe->fcp_tsend.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0); + bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0); + bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0); + bf_set(wqe_pbde, &wqe->fcp_tsend.wqe_com, 0); + + /* Word 12 - fcp_data_len is variable */ + + /* Word 13, 14, 15 - PBDE is zero */ + + /* TRECEIVE template */ + wqe = &lpfc_treceive_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 */ + wqe->fcp_treceive.payload_offset_len = TXRDY_PAYLOAD_LEN; + + /* Word 4 - relative_offset is variable */ + + /* Word 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_treceive.wqe_com, CMD_FCP_TRECEIVE64_WQE); + bf_set(wqe_pu, &wqe->fcp_treceive.wqe_com, PARM_REL_OFF); + bf_set(wqe_class, &wqe->fcp_treceive.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_treceive.wqe_com, SLI4_CT_RPI); + bf_set(wqe_ar, &wqe->fcp_treceive.wqe_com, 0); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag, rcvoxid is variable */ + + /* Word 10 - xc is variable */ + bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0); + bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, LPFC_WQE_LENLOC_WORD12); + bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com, FCP_COMMAND_TRECEIVE); + bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_sup, &wqe->fcp_treceive.wqe_com, 0); + bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0); + bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0); + bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 1); + + /* Word 12 - fcp_data_len is variable */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* TRSP template */ + wqe = &lpfc_trsp_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - response_len is variable */ + + /* Word 4, 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_trsp.wqe_com, CMD_FCP_TRSP64_WQE); + bf_set(wqe_pu, &wqe->fcp_trsp.wqe_com, PARM_UNUSED); + bf_set(wqe_class, &wqe->fcp_trsp.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_trsp.wqe_com, SLI4_CT_RPI); + bf_set(wqe_ag, &wqe->fcp_trsp.wqe_com, 1); /* wqe_ar */ + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 wqes, xc is variable */ + bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 1); + bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0); + bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_NONE); + bf_set(wqe_lenloc, &wqe->fcp_trsp.wqe_com, LPFC_WQE_LENLOC_WORD3); + + /* Word 11 irsp, irsplen is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_trsp.wqe_com, FCP_COMMAND_TRSP); + bf_set(wqe_cqid, &wqe->fcp_trsp.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_sup, &wqe->fcp_trsp.wqe_com, 0); + bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0); + bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0); + bf_set(wqe_pbde, &wqe->fcp_trsp.wqe_com, 0); + + /* Word 12, 13, 14, 15 - is zero */ +} void lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) @@ -130,7 +275,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if (tgtp) { if (status) { atomic_inc(&tgtp->xmt_ls_rsp_error); - if (status == IOERR_ABORT_REQUESTED) + if (result == IOERR_ABORT_REQUESTED) atomic_inc(&tgtp->xmt_ls_rsp_aborted); if (bf_get(lpfc_wcqe_c_xb, wcqe)) atomic_inc(&tgtp->xmt_ls_rsp_xb_set); @@ -268,8 +413,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) "NVMET RCV BUSY: xri x%x sz %d " "from %06x\n", oxid, size, sid); - /* defer repost rcv buffer till .defer_rcv callback */ - ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST; atomic_inc(&tgtp->rcv_fcp_cmd_out); return; } @@ -541,7 +684,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, rsp->transferred_length = 0; if (tgtp) { atomic_inc(&tgtp->xmt_fcp_rsp_error); - if (status == IOERR_ABORT_REQUESTED) + if (result == IOERR_ABORT_REQUESTED) atomic_inc(&tgtp->xmt_fcp_rsp_aborted); } @@ -741,7 +884,10 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, struct lpfc_nvmet_rcv_ctx *ctxp = container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); struct lpfc_hba *phba = ctxp->phba; + struct lpfc_queue *wq; struct lpfc_iocbq *nvmewqeq; + struct lpfc_sli_ring *pring; + unsigned long iflags; int rc; if (phba->pport->load_flag & FC_UNLOADING) { @@ -820,6 +966,22 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, return 0; } + if (rc == -EBUSY) { + /* + * WQ was full, so queue nvmewqeq to be sent after + * WQE release CQE + */ + ctxp->flag |= LPFC_NVMET_DEFER_WQFULL; + wq = phba->sli4_hba.nvme_wq[rsp->hwqid]; + pring = wq->pring; + spin_lock_irqsave(&pring->ring_lock, iflags); + list_add_tail(&nvmewqeq->list, &wq->wqfull_list); + wq->q_flag |= HBA_NVMET_WQFULL; + spin_unlock_irqrestore(&pring->ring_lock, iflags); + atomic_inc(&lpfc_nvmep->defer_wqfull); + return 0; + } + /* Give back resources */ atomic_inc(&lpfc_nvmep->xmt_fcp_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, @@ -851,6 +1013,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, struct lpfc_nvmet_rcv_ctx *ctxp = container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); struct lpfc_hba *phba = ctxp->phba; + struct lpfc_queue *wq; unsigned long flags; if (phba->pport->load_flag & FC_UNLOADING) @@ -880,6 +1043,15 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, } ctxp->flag |= LPFC_NVMET_ABORT_OP; + if (ctxp->flag & LPFC_NVMET_DEFER_WQFULL) { + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + wq = phba->sli4_hba.nvme_wq[ctxp->wqeq->hba_wqidx]; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + lpfc_nvmet_wqfull_flush(phba, wq, ctxp); + return; + } + /* An state of LPFC_NVMET_STE_RCV means we have just received * the NVME command and have not started processing it. * (by issuing any IO WQEs on this exchange yet) @@ -946,11 +1118,9 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, tgtp = phba->targetport->private; atomic_inc(&tgtp->rcv_fcp_cmd_defer); - if (ctxp->flag & LPFC_NVMET_DEFER_RCV_REPOST) - lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ - else - nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); - ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST; + + /* Free the nvmebuf since a new buffer already replaced it */ + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); } static struct nvmet_fc_target_template lpfc_tgttemplate = { @@ -1124,16 +1294,10 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) } ctx_buf->iocbq->iocb_flag = LPFC_IO_NVMET; nvmewqe = ctx_buf->iocbq; - wqe = (union lpfc_wqe128 *)&nvmewqe->wqe; + wqe = &nvmewqe->wqe; + /* Initialize WQE */ memset(wqe, 0, sizeof(union lpfc_wqe)); - /* Word 7 */ - bf_set(wqe_ct, &wqe->generic.wqe_com, SLI4_CT_RPI); - bf_set(wqe_class, &wqe->generic.wqe_com, CLASS3); - /* Word 10 */ - bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1); - bf_set(wqe_ebde_cnt, &wqe->generic.wqe_com, 0); - bf_set(wqe_qosd, &wqe->generic.wqe_com, 0); ctx_buf->iocbq->context1 = NULL; spin_lock(&phba->sli4_hba.sgl_list_lock); @@ -1280,6 +1444,9 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) atomic_set(&tgtp->xmt_abort_sol, 0); atomic_set(&tgtp->xmt_abort_rsp, 0); atomic_set(&tgtp->xmt_abort_rsp_error, 0); + atomic_set(&tgtp->defer_ctx, 0); + atomic_set(&tgtp->defer_fod, 0); + atomic_set(&tgtp->defer_wqfull, 0); } return error; } @@ -1435,16 +1602,103 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, return 0; } +static void +lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, + struct lpfc_nvmet_rcv_ctx *ctxp) +{ + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *nvmewqeq; + struct lpfc_iocbq *next_nvmewqeq; + unsigned long iflags; + struct lpfc_wcqe_complete wcqe; + struct lpfc_wcqe_complete *wcqep; + + pring = wq->pring; + wcqep = &wcqe; + + /* Fake an ABORT error code back to cmpl routine */ + memset(wcqep, 0, sizeof(struct lpfc_wcqe_complete)); + bf_set(lpfc_wcqe_c_status, wcqep, IOSTAT_LOCAL_REJECT); + wcqep->parameter = IOERR_ABORT_REQUESTED; + + spin_lock_irqsave(&pring->ring_lock, iflags); + list_for_each_entry_safe(nvmewqeq, next_nvmewqeq, + &wq->wqfull_list, list) { + if (ctxp) { + /* Checking for a specific IO to flush */ + if (nvmewqeq->context2 == ctxp) { + list_del(&nvmewqeq->list); + spin_unlock_irqrestore(&pring->ring_lock, + iflags); + lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, + wcqep); + return; + } + continue; + } else { + /* Flush all IOs */ + list_del(&nvmewqeq->list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep); + spin_lock_irqsave(&pring->ring_lock, iflags); + } + } + if (!ctxp) + wq->q_flag &= ~HBA_NVMET_WQFULL; + spin_unlock_irqrestore(&pring->ring_lock, iflags); +} + +void +lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, + struct lpfc_queue *wq) +{ +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *nvmewqeq; + unsigned long iflags; + int rc; + + /* + * Some WQE slots are available, so try to re-issue anything + * on the WQ wqfull_list. + */ + pring = wq->pring; + spin_lock_irqsave(&pring->ring_lock, iflags); + while (!list_empty(&wq->wqfull_list)) { + list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq, + list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + rc = lpfc_sli4_issue_wqe(phba, LPFC_FCP_RING, nvmewqeq); + spin_lock_irqsave(&pring->ring_lock, iflags); + if (rc == -EBUSY) { + /* WQ was full again, so put it back on the list */ + list_add(&nvmewqeq->list, &wq->wqfull_list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + return; + } + } + wq->q_flag &= ~HBA_NVMET_WQFULL; + spin_unlock_irqrestore(&pring->ring_lock, iflags); + +#endif +} + void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) { #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_nvmet_tgtport *tgtp; + struct lpfc_queue *wq; + uint32_t qidx; if (phba->nvmet_support == 0) return; if (phba->targetport) { tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++) { + wq = phba->sli4_hba.nvme_wq[qidx]; + lpfc_nvmet_wqfull_flush(phba, wq, NULL); + } init_completion(&tgtp->tport_unreg_done); nvmet_fc_unregister_targetport(phba->targetport); wait_for_completion_timeout(&tgtp->tport_unreg_done, 5); @@ -1694,6 +1948,8 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, lpfc_nvmeio_data(phba, "NVMET FCP RCV: xri x%x sz %d CPU %02x\n", oxid, size, smp_processor_id()); + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + if (!ctx_buf) { /* Queue this NVME IO to process later */ spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); @@ -1709,10 +1965,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, lpfc_post_rq_buffer( phba, phba->sli4_hba.nvmet_mrq_hdr[qno], phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); + + atomic_inc(&tgtp->defer_ctx); return; } - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; payload = (uint32_t *)(nvmebuf->dbuf.virt); sid = sli4_sid_from_fc_hdr(fc_hdr); @@ -1776,12 +2033,20 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, /* Processing of FCP command is deferred */ if (rc == -EOVERFLOW) { + /* + * Post a brand new DMA buffer to RQ and defer + * freeing rcv buffer till .defer_rcv callback + */ + qno = nvmebuf->idx; + lpfc_post_rq_buffer( + phba, phba->sli4_hba.nvmet_mrq_hdr[qno], + phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); + lpfc_nvmeio_data(phba, "NVMET RCV BUSY: xri x%x sz %d from %06x\n", oxid, size, sid); - /* defer reposting rcv buffer till .defer_rcv callback */ - ctxp->flag |= LPFC_NVMET_DEFER_RCV_REPOST; atomic_inc(&tgtp->rcv_fcp_cmd_out); + atomic_inc(&tgtp->defer_fod); return; } ctxp->rqb_buffer = nvmebuf; @@ -1897,7 +2162,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, { struct lpfc_nodelist *ndlp; struct lpfc_iocbq *nvmewqe; - union lpfc_wqe *wqe; + union lpfc_wqe128 *wqe; if (!lpfc_is_link_up(phba)) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, @@ -2023,9 +2288,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *nvmewqe; struct scatterlist *sgel; union lpfc_wqe128 *wqe; + struct ulp_bde64 *bde; uint32_t *txrdy; dma_addr_t physaddr; int i, cnt; + int do_pbde; int xc = 1; if (!lpfc_is_link_up(phba)) { @@ -2078,7 +2345,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (((ctxp->state == LPFC_NVMET_STE_RCV) && (ctxp->entry_cnt == 1)) || (ctxp->state == LPFC_NVMET_STE_DATA)) { - wqe = (union lpfc_wqe128 *)&nvmewqe->wqe; + wqe = &nvmewqe->wqe; } else { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "6111 Wrong state NVMET FCP: %d cnt %d\n", @@ -2090,6 +2357,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, switch (rsp->op) { case NVMET_FCOP_READDATA: case NVMET_FCOP_READDATA_RSP: + /* From the tsend template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_tsend_cmd_template.words[7], + sizeof(uint32_t) * 5); + /* Words 0 - 2 : The first sg segment */ sgel = &rsp->sg[0]; physaddr = sg_dma_address(sgel); @@ -2106,6 +2378,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, wqe->fcp_tsend.relative_offset = ctxp->offset; /* Word 5 */ + wqe->fcp_tsend.reserved = 0; /* Word 6 */ bf_set(wqe_ctxt_tag, &wqe->fcp_tsend.wqe_com, @@ -2113,9 +2386,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(wqe_xri_tag, &wqe->fcp_tsend.wqe_com, nvmewqe->sli4_xritag); - /* Word 7 */ - bf_set(wqe_pu, &wqe->fcp_tsend.wqe_com, 1); - bf_set(wqe_cmnd, &wqe->fcp_tsend.wqe_com, CMD_FCP_TSEND64_WQE); + /* Word 7 - set ar later */ /* Word 8 */ wqe->fcp_tsend.wqe_com.abort_tag = nvmewqe->iotag; @@ -2124,23 +2395,12 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(wqe_reqtag, &wqe->fcp_tsend.wqe_com, nvmewqe->iotag); bf_set(wqe_rcvoxid, &wqe->fcp_tsend.wqe_com, ctxp->oxid); - /* Word 10 */ - bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1); - bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_tsend.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_tsend.wqe_com, - LPFC_WQE_LENLOC_WORD12); - bf_set(wqe_ebde_cnt, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, xc); - bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1); - if (phba->cfg_nvme_oas) - bf_set(wqe_oas, &wqe->fcp_tsend.wqe_com, 1); + /* Word 10 - set wqes later, in template xc=1 */ + if (!xc) + bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 0); - /* Word 11 */ - bf_set(wqe_cqid, &wqe->fcp_tsend.wqe_com, - LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_cmd_type, &wqe->fcp_tsend.wqe_com, - FCP_COMMAND_TSEND); + /* Word 11 - set sup, irsp, irsplen later */ + do_pbde = 0; /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; @@ -2162,15 +2422,14 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, sgl++; if (rsp->op == NVMET_FCOP_READDATA_RSP) { atomic_inc(&tgtp->xmt_fcp_read_rsp); - bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1); - if ((ndlp->nlp_flag & NLP_SUPPRESS_RSP) && - (rsp->rsplen == 12)) { - bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 1); - bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0); + + /* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */ + + if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) { + if (ndlp->nlp_flag & NLP_SUPPRESS_RSP) + bf_set(wqe_sup, + &wqe->fcp_tsend.wqe_com, 1); } else { - bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0); bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 1); bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 1); bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, @@ -2181,15 +2440,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } else { atomic_inc(&tgtp->xmt_fcp_read); - bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0); + /* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */ bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 0); - bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0); } break; case NVMET_FCOP_WRITEDATA: + /* From the treceive template, initialize words 3 - 11 */ + memcpy(&wqe->words[3], + &lpfc_treceive_cmd_template.words[3], + sizeof(uint32_t) * 9); + /* Words 0 - 2 : The first sg segment */ txrdy = dma_pool_alloc(phba->txrdy_payload_pool, GFP_KERNEL, &physaddr); @@ -2208,14 +2469,9 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, wqe->fcp_treceive.bde.addrHigh = cpu_to_le32(putPaddrHigh(physaddr)); - /* Word 3 */ - wqe->fcp_treceive.payload_offset_len = TXRDY_PAYLOAD_LEN; - /* Word 4 */ wqe->fcp_treceive.relative_offset = ctxp->offset; - /* Word 5 */ - /* Word 6 */ bf_set(wqe_ctxt_tag, &wqe->fcp_treceive.wqe_com, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); @@ -2223,10 +2479,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, nvmewqe->sli4_xritag); /* Word 7 */ - bf_set(wqe_pu, &wqe->fcp_treceive.wqe_com, 1); - bf_set(wqe_ar, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_cmnd, &wqe->fcp_treceive.wqe_com, - CMD_FCP_TRECEIVE64_WQE); /* Word 8 */ wqe->fcp_treceive.wqe_com.abort_tag = nvmewqe->iotag; @@ -2235,26 +2487,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(wqe_reqtag, &wqe->fcp_treceive.wqe_com, nvmewqe->iotag); bf_set(wqe_rcvoxid, &wqe->fcp_treceive.wqe_com, ctxp->oxid); - /* Word 10 */ - bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1); - bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, - LPFC_WQE_LENLOC_WORD12); - bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, xc); - bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1); - if (phba->cfg_nvme_oas) - bf_set(wqe_oas, &wqe->fcp_treceive.wqe_com, 1); + /* Word 10 - in template xc=1 */ + if (!xc) + bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, 0); - /* Word 11 */ - bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com, - LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com, - FCP_COMMAND_TRECEIVE); - bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0); + /* Word 11 - set pbde later */ + if (phba->nvme_embed_pbde) { + do_pbde = 1; + } else { + bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 0); + do_pbde = 0; + } /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; @@ -2282,6 +2525,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, break; case NVMET_FCOP_RSP: + /* From the treceive template, initialize words 4 - 11 */ + memcpy(&wqe->words[4], + &lpfc_trsp_cmd_template.words[4], + sizeof(uint32_t) * 8); + /* Words 0 - 2 */ physaddr = rsp->rspdma; wqe->fcp_trsp.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; @@ -2294,12 +2542,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, /* Word 3 */ wqe->fcp_trsp.response_len = rsp->rsplen; - /* Word 4 */ - wqe->fcp_trsp.rsvd_4_5[0] = 0; - - - /* Word 5 */ - /* Word 6 */ bf_set(wqe_ctxt_tag, &wqe->fcp_trsp.wqe_com, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); @@ -2307,9 +2549,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, nvmewqe->sli4_xritag); /* Word 7 */ - bf_set(wqe_pu, &wqe->fcp_trsp.wqe_com, 0); - bf_set(wqe_ag, &wqe->fcp_trsp.wqe_com, 1); - bf_set(wqe_cmnd, &wqe->fcp_trsp.wqe_com, CMD_FCP_TRSP64_WQE); /* Word 8 */ wqe->fcp_trsp.wqe_com.abort_tag = nvmewqe->iotag; @@ -2319,35 +2558,23 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(wqe_rcvoxid, &wqe->fcp_trsp.wqe_com, ctxp->oxid); /* Word 10 */ - bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1); - bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 0); - bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_trsp.wqe_com, - LPFC_WQE_LENLOC_WORD3); - bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, xc); - bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1); - if (phba->cfg_nvme_oas) - bf_set(wqe_oas, &wqe->fcp_trsp.wqe_com, 1); + if (xc) + bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 1); /* Word 11 */ - bf_set(wqe_cqid, &wqe->fcp_trsp.wqe_com, - LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_cmd_type, &wqe->fcp_trsp.wqe_com, - FCP_COMMAND_TRSP); - bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0); - - if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) { - /* Good response - all zero's on wire */ - bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0); - bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0); - bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0); - } else { + /* In template wqes=0 irsp=0 irsplen=0 - good response */ + if (rsp->rsplen != LPFC_NVMET_SUCCESS_LEN) { + /* Bad response - embed it */ bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 1); bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 1); bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, ((rsp->rsplen >> 2) - 1)); memcpy(&wqe->words[16], rsp->rspaddr, rsp->rsplen); } + do_pbde = 0; + + /* Word 12 */ + wqe->fcp_trsp.rsvd_12_15[0] = 0; /* Use rspbuf, NOT sg list */ rsp->sg_cnt = 0; @@ -2380,6 +2607,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(cnt); + if (do_pbde && i == 0) { + bde = (struct ulp_bde64 *)&wqe->words[13]; + memset(bde, 0, sizeof(struct ulp_bde64)); + /* Words 13-15 (PBDE)*/ + bde->addrLow = sgl->addr_lo; + bde->addrHigh = sgl->addr_hi; + bde->tus.f.bdeSize = + le32_to_cpu(sgl->sge_len); + bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bde->tus.w = cpu_to_le32(bde->tus.w); + } sgl++; ctxp->offset += cnt; } @@ -2597,7 +2835,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; - union lpfc_wqe *wqe_abts; + union lpfc_wqe128 *wqe_abts; struct lpfc_nodelist *ndlp; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, @@ -2692,7 +2930,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; - union lpfc_wqe *abts_wqe; + union lpfc_wqe128 *abts_wqe; struct lpfc_nodelist *ndlp; unsigned long flags; int rc; @@ -2882,7 +3120,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; - union lpfc_wqe *wqe_abts; + union lpfc_wqe128 *wqe_abts; unsigned long flags; int rc; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 5b32c9e4d4ef..c1bcef3f103c 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -72,7 +72,6 @@ struct lpfc_nvmet_tgtport { atomic_t xmt_fcp_rsp_aborted; atomic_t xmt_fcp_rsp_drop; - /* Stats counters - lpfc_nvmet_xmt_fcp_abort */ atomic_t xmt_fcp_xri_abort_cqe; atomic_t xmt_fcp_abort; @@ -81,6 +80,11 @@ struct lpfc_nvmet_tgtport { atomic_t xmt_abort_unsol; atomic_t xmt_abort_rsp; atomic_t xmt_abort_rsp_error; + + /* Stats counters - defer IO */ + atomic_t defer_ctx; + atomic_t defer_fod; + atomic_t defer_wqfull; }; struct lpfc_nvmet_ctx_info { @@ -131,7 +135,7 @@ struct lpfc_nvmet_rcv_ctx { #define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ #define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ #define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ -#define LPFC_NVMET_DEFER_RCV_REPOST 0x20 /* repost to RQ on defer rcv */ +#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ struct rqb_dmabuf *rqb_buffer; struct lpfc_nvmet_ctxbuf *ctxbuf; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c0cdaef4db24..050f04418f5f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -837,8 +837,13 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) * 4K Page alignment is CRITICAL to BlockGuard, double check * to be sure. */ - if (phba->cfg_enable_bg && (((unsigned long)(psb->data) & + if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) && + (((unsigned long)(psb->data) & (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "3369 Memory alignment error " + "addr=%lx\n", + (unsigned long)psb->data); dma_pool_free(phba->lpfc_sg_dma_buf_pool, psb->data, psb->dma_handle); kfree(psb); @@ -3304,8 +3309,12 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) dma_offset += dma_len; sgl++; } - /* setup the performance hint (first data BDE) if enabled */ - if (phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) { + /* + * Setup the first Payload BDE. For FCoE we just key off + * Performance Hints, for FC we utilize fcp_embed_pbde. + */ + if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || + phba->fcp_embed_pbde) { bde = (struct ulp_bde64 *) &(iocb_cmd->unsli3.sli3Words[5]); bde->addrLow = first_data_sgl->addr_lo; @@ -3772,20 +3781,18 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId)); lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER, - "9025 FCP Read Underrun, expected %d, " + "9025 FCP Underrun, expected %d, " "residual %d Data: x%x x%x x%x\n", fcpDl, scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0], cmnd->underflow); /* - * If there is an under run check if under run reported by + * If there is an under run, check if under run reported by * storage array is same as the under run reported by HBA. * If this is not same, there is a dropped frame. */ - if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && - fcpi_parm && - (scsi_get_resid(cmnd) != fcpi_parm)) { + if (fcpi_parm && (scsi_get_resid(cmnd) != fcpi_parm)) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, "9026 FCP Read Check Error " @@ -3926,7 +3933,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; struct scsi_cmnd *cmd; - int depth; unsigned long flags; struct lpfc_fast_path_event *fast_path_evt; struct Scsi_Host *shost; @@ -4132,16 +4138,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } spin_unlock_irqrestore(shost->host_lock, flags); } else if (pnode && NLP_CHK_NODE_ACT(pnode)) { - if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) && - time_after(jiffies, pnode->last_change_time + + if ((pnode->cmd_qdepth != vport->cfg_tgt_queue_depth) && + time_after(jiffies, pnode->last_change_time + msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { spin_lock_irqsave(shost->host_lock, flags); - depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT - / 100; - depth = depth ? depth : 1; - pnode->cmd_qdepth += depth; - if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth) - pnode->cmd_qdepth = vport->cfg_tgt_queue_depth; + pnode->cmd_qdepth = vport->cfg_tgt_queue_depth; pnode->last_change_time = jiffies; spin_unlock_irqrestore(shost->host_lock, flags); } @@ -4564,9 +4565,32 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) */ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) goto out_tgt_busy; - if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) + if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_ERROR, + "3377 Target Queue Full, scsi Id:%d Qdepth:%d" + " Pending command:%d" + " WWNN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, " + " WWPN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + ndlp->nlp_sid, ndlp->cmd_qdepth, + atomic_read(&ndlp->cmd_pending), + ndlp->nlp_nodename.u.wwn[0], + ndlp->nlp_nodename.u.wwn[1], + ndlp->nlp_nodename.u.wwn[2], + ndlp->nlp_nodename.u.wwn[3], + ndlp->nlp_nodename.u.wwn[4], + ndlp->nlp_nodename.u.wwn[5], + ndlp->nlp_nodename.u.wwn[6], + ndlp->nlp_nodename.u.wwn[7], + ndlp->nlp_portname.u.wwn[0], + ndlp->nlp_portname.u.wwn[1], + ndlp->nlp_portname.u.wwn[2], + ndlp->nlp_portname.u.wwn[3], + ndlp->nlp_portname.u.wwn[4], + ndlp->nlp_portname.u.wwn[5], + ndlp->nlp_portname.u.wwn[6], + ndlp->nlp_portname.u.wwn[7]); goto out_tgt_busy; - + } lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp); if (lpfc_cmd == NULL) { lpfc_rampdown_queue_depth(phba); diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 5da7e15400cb..8e38e0204c47 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 5f5528a12308..cb17e2b2be81 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,8 +1,7 @@ - /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -36,6 +35,9 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> #include <linux/aer.h> +#ifdef CONFIG_X86 +#include <asm/set_memory.h> +#endif #include <linux/nvme-fc-driver.h> @@ -107,12 +109,14 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) * The caller is expected to hold the hbalock when calling this routine. **/ static int -lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) +lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) { union lpfc_wqe *temp_wqe; struct lpfc_register doorbell; uint32_t host_index; uint32_t idx; + uint32_t i = 0; + uint8_t *tmp; /* sanity check on queue memory */ if (unlikely(!q)) @@ -129,10 +133,25 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* set consumption flag every once in a while */ if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); + else + bf_set(wqe_wqec, &wqe->generic.wqe_com, 0); if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); - /* ensure WQE bcopy flushed before doorbell write */ + if (q->dpp_enable && q->phba->cfg_enable_dpp) { + /* write to DPP aperture taking advatage of Combined Writes */ + tmp = (uint8_t *)temp_wqe; +#ifdef __raw_writeq + for (i = 0; i < q->entry_size; i += sizeof(uint64_t)) + __raw_writeq(*((uint64_t *)(tmp + i)), + q->dpp_regaddr + i); +#else + for (i = 0; i < q->entry_size; i += sizeof(uint32_t)) + __raw_writel(*((uint32_t *)(tmp + i)), + q->dpp_regaddr + i); +#endif + } + /* ensure WQE bcopy and DPP flushed before doorbell write */ wmb(); /* Update the host index before invoking device */ @@ -143,9 +162,18 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* Ring Doorbell */ doorbell.word0 = 0; if (q->db_format == LPFC_DB_LIST_FORMAT) { - bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1); - bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index); - bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id); + if (q->dpp_enable && q->phba->cfg_enable_dpp) { + bf_set(lpfc_if6_wq_db_list_fm_num_posted, &doorbell, 1); + bf_set(lpfc_if6_wq_db_list_fm_dpp, &doorbell, 1); + bf_set(lpfc_if6_wq_db_list_fm_dpp_id, &doorbell, + q->dpp_id); + bf_set(lpfc_if6_wq_db_list_fm_id, &doorbell, + q->queue_id); + } else { + bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1); + bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index); + bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id); + } } else if (q->db_format == LPFC_DB_RING_FORMAT) { bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1); bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id); @@ -262,16 +290,18 @@ lpfc_sli4_mq_release(struct lpfc_queue *q) static struct lpfc_eqe * lpfc_sli4_eq_get(struct lpfc_queue *q) { + struct lpfc_hba *phba; struct lpfc_eqe *eqe; uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) return NULL; + phba = q->phba; eqe = q->qe[q->hba_index].eqe; /* If the next EQE is not valid then we are done */ - if (!bf_get_le32(lpfc_eqe_valid, eqe)) + if (bf_get_le32(lpfc_eqe_valid, eqe) != q->qe_valid) return NULL; /* If the host has not yet processed the next entry then we are done */ idx = ((q->hba_index + 1) % q->entry_count); @@ -279,6 +309,10 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) return NULL; q->hba_index = idx; + /* if the index wrapped around, toggle the valid bit */ + if (phba->sli4_hba.pc_sli4_params.eqav && !q->hba_index) + q->qe_valid = (q->qe_valid) ? 0 : 1; + /* * insert barrier for instruction interlock : data from the hardware @@ -298,7 +332,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) * @q: The Event Queue to disable interrupts * **/ -static inline void +inline void lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) { struct lpfc_register doorbell; @@ -309,7 +343,26 @@ lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); + writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); +} + +/** + * lpfc_sli4_if6_eq_clr_intr - Turn off interrupts from this EQ + * @q: The Event Queue to disable interrupts + * + **/ +inline void +lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q) +{ + struct lpfc_register doorbell; + + doorbell.word0 = 0; + bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); + bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); + bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, + (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); + bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); } /** @@ -331,17 +384,21 @@ uint32_t lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) { uint32_t released = 0; + struct lpfc_hba *phba; struct lpfc_eqe *temp_eqe; struct lpfc_register doorbell; /* sanity check on queue memory */ if (unlikely(!q)) return 0; + phba = q->phba; /* while there are valid entries */ while (q->hba_index != q->host_index) { - temp_eqe = q->qe[q->host_index].eqe; - bf_set_le32(lpfc_eqe_valid, temp_eqe, 0); + if (!phba->sli4_hba.pc_sli4_params.eqav) { + temp_eqe = q->qe[q->host_index].eqe; + bf_set_le32(lpfc_eqe_valid, temp_eqe, 0); + } released++; q->host_index = ((q->host_index + 1) % q->entry_count); } @@ -359,10 +416,63 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); + writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); /* PCI read to flush PCI pipeline on re-arming for INTx mode */ if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) - readl(q->phba->sli4_hba.EQCQDBregaddr); + readl(q->phba->sli4_hba.EQDBregaddr); + return released; +} + +/** + * lpfc_sli4_if6_eq_release - Indicates the host has finished processing an EQ + * @q: The Event Queue that the host has completed processing for. + * @arm: Indicates whether the host wants to arms this CQ. + * + * This routine will mark all Event Queue Entries on @q, from the last + * known completed entry to the last entry that was processed, as completed + * by clearing the valid bit for each completion queue entry. Then it will + * notify the HBA, by ringing the doorbell, that the EQEs have been processed. + * The internal host index in the @q will be updated by this routine to indicate + * that the host has finished processing the entries. The @arm parameter + * indicates that the queue should be rearmed when ringing the doorbell. + * + * This function will return the number of EQEs that were popped. + **/ +uint32_t +lpfc_sli4_if6_eq_release(struct lpfc_queue *q, bool arm) +{ + uint32_t released = 0; + struct lpfc_hba *phba; + struct lpfc_eqe *temp_eqe; + struct lpfc_register doorbell; + + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + phba = q->phba; + + /* while there are valid entries */ + while (q->hba_index != q->host_index) { + if (!phba->sli4_hba.pc_sli4_params.eqav) { + temp_eqe = q->qe[q->host_index].eqe; + bf_set_le32(lpfc_eqe_valid, temp_eqe, 0); + } + released++; + q->host_index = ((q->host_index + 1) % q->entry_count); + } + if (unlikely(released == 0 && !arm)) + return 0; + + /* ring doorbell for number popped */ + doorbell.word0 = 0; + if (arm) + bf_set(lpfc_if6_eq_doorbell_arm, &doorbell, 1); + bf_set(lpfc_if6_eq_doorbell_num_released, &doorbell, released); + bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr); + /* PCI read to flush PCI pipeline on re-arming for INTx mode */ + if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) + readl(q->phba->sli4_hba.EQDBregaddr); return released; } @@ -378,23 +488,28 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) static struct lpfc_cqe * lpfc_sli4_cq_get(struct lpfc_queue *q) { + struct lpfc_hba *phba; struct lpfc_cqe *cqe; uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) return NULL; + phba = q->phba; + cqe = q->qe[q->hba_index].cqe; /* If the next CQE is not valid then we are done */ - if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) + if (bf_get_le32(lpfc_cqe_valid, cqe) != q->qe_valid) return NULL; /* If the host has not yet processed the next entry then we are done */ idx = ((q->hba_index + 1) % q->entry_count); if (idx == q->host_index) return NULL; - cqe = q->qe[q->hba_index].cqe; q->hba_index = idx; + /* if the index wrapped around, toggle the valid bit */ + if (phba->sli4_hba.pc_sli4_params.cqav && !q->hba_index) + q->qe_valid = (q->qe_valid) ? 0 : 1; /* * insert barrier for instruction interlock : data from the hardware @@ -427,16 +542,21 @@ uint32_t lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) { uint32_t released = 0; + struct lpfc_hba *phba; struct lpfc_cqe *temp_qe; struct lpfc_register doorbell; /* sanity check on queue memory */ if (unlikely(!q)) return 0; + phba = q->phba; + /* while there are valid entries */ while (q->hba_index != q->host_index) { - temp_qe = q->qe[q->host_index].cqe; - bf_set_le32(lpfc_cqe_valid, temp_qe, 0); + if (!phba->sli4_hba.pc_sli4_params.cqav) { + temp_qe = q->qe[q->host_index].cqe; + bf_set_le32(lpfc_cqe_valid, temp_qe, 0); + } released++; q->host_index = ((q->host_index + 1) % q->entry_count); } @@ -452,7 +572,57 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell, (q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT)); bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); + writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr); + return released; +} + +/** + * lpfc_sli4_if6_cq_release - Indicates the host has finished processing a CQ + * @q: The Completion Queue that the host has completed processing for. + * @arm: Indicates whether the host wants to arms this CQ. + * + * This routine will mark all Completion queue entries on @q, from the last + * known completed entry to the last entry that was processed, as completed + * by clearing the valid bit for each completion queue entry. Then it will + * notify the HBA, by ringing the doorbell, that the CQEs have been processed. + * The internal host index in the @q will be updated by this routine to indicate + * that the host has finished processing the entries. The @arm parameter + * indicates that the queue should be rearmed when ringing the doorbell. + * + * This function will return the number of CQEs that were released. + **/ +uint32_t +lpfc_sli4_if6_cq_release(struct lpfc_queue *q, bool arm) +{ + uint32_t released = 0; + struct lpfc_hba *phba; + struct lpfc_cqe *temp_qe; + struct lpfc_register doorbell; + + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + phba = q->phba; + + /* while there are valid entries */ + while (q->hba_index != q->host_index) { + if (!phba->sli4_hba.pc_sli4_params.cqav) { + temp_qe = q->qe[q->host_index].cqe; + bf_set_le32(lpfc_cqe_valid, temp_qe, 0); + } + released++; + q->host_index = ((q->host_index + 1) % q->entry_count); + } + if (unlikely(released == 0 && !arm)) + return 0; + + /* ring doorbell for number popped */ + doorbell.word0 = 0; + if (arm) + bf_set(lpfc_if6_cq_doorbell_arm, &doorbell, 1); + bf_set(lpfc_if6_cq_doorbell_num_released, &doorbell, released); + bf_set(lpfc_if6_cq_doorbell_cqid, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr); return released; } @@ -2218,18 +2388,18 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) void lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) { - wait_queue_head_t *pdone_q; unsigned long drvr_flag; + struct completion *pmbox_done; /* - * If pdone_q is empty, the driver thread gave up waiting and + * If pmbox_done is empty, the driver thread gave up waiting and * continued running. */ pmboxq->mbox_flag |= LPFC_MBX_WAKE; spin_lock_irqsave(&phba->hbalock, drvr_flag); - pdone_q = (wait_queue_head_t *) pmboxq->context1; - if (pdone_q) - wake_up_interruptible(pdone_q); + pmbox_done = (struct completion *)pmboxq->context3; + if (pmbox_done) + complete(pmbox_done); spin_unlock_irqrestore(&phba->hbalock, drvr_flag); return; } @@ -2330,7 +2500,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) { if (phba->sli_rev == LPFC_SLI_REV4 && (bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf) == + &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2)) { if (ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, @@ -3776,6 +3946,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; uint32_t i; + struct lpfc_iocbq *piocb, *next_iocb; spin_lock_irq(&phba->hbalock); /* Indicate the I/O queues are flushed */ @@ -3790,6 +3961,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) spin_lock_irq(&pring->ring_lock); /* Retrieve everything on txq */ list_splice_init(&pring->txq, &txq); + list_for_each_entry_safe(piocb, next_iocb, + &pring->txcmplq, list) + piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txq_cnt = 0; @@ -3811,6 +3985,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); /* Retrieve everything on txq */ list_splice_init(&pring->txq, &txq); + list_for_each_entry_safe(piocb, next_iocb, + &pring->txcmplq, list) + piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txq_cnt = 0; @@ -3842,6 +4019,7 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba) LIST_HEAD(txcmplq); struct lpfc_sli_ring *pring; uint32_t i; + struct lpfc_iocbq *piocb, *next_iocb; if (phba->sli_rev < LPFC_SLI_REV4) return; @@ -3858,8 +4036,11 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba) for (i = 0; i < phba->cfg_nvme_io_channel; i++) { pring = phba->sli4_hba.nvme_wq[i]->pring; - /* Retrieve everything on the txcmplq */ spin_lock_irq(&pring->ring_lock); + list_for_each_entry_safe(piocb, next_iocb, + &pring->txcmplq, list) + piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txcmplq_cnt = 0; spin_unlock_irq(&pring->ring_lock); @@ -4812,13 +4993,14 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; phba->port_gp = phba->mbox->us.s3_pgp.port; - if (phba->cfg_enable_bg) { - if (pmb->u.mb.un.varCfgPort.gbg) - phba->sli3_options |= LPFC_SLI3_BG_ENABLED; - else + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { + if (pmb->u.mb.un.varCfgPort.gbg == 0) { + phba->cfg_enable_bg = 0; + phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0443 Adapter did not grant " "BlockGuard\n"); + } } } else { phba->hbq_get = NULL; @@ -5290,41 +5472,42 @@ static void lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) { int qidx; + struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba; - lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); - lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); - if (phba->sli4_hba.nvmels_cq) - lpfc_sli4_cq_release(phba->sli4_hba.nvmels_cq, + sli4_hba->sli4_cq_release(sli4_hba->mbx_cq, LPFC_QUEUE_REARM); + sli4_hba->sli4_cq_release(sli4_hba->els_cq, LPFC_QUEUE_REARM); + if (sli4_hba->nvmels_cq) + sli4_hba->sli4_cq_release(sli4_hba->nvmels_cq, LPFC_QUEUE_REARM); - if (phba->sli4_hba.fcp_cq) + if (sli4_hba->fcp_cq) for (qidx = 0; qidx < phba->cfg_fcp_io_channel; qidx++) - lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[qidx], + sli4_hba->sli4_cq_release(sli4_hba->fcp_cq[qidx], LPFC_QUEUE_REARM); - if (phba->sli4_hba.nvme_cq) + if (sli4_hba->nvme_cq) for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++) - lpfc_sli4_cq_release(phba->sli4_hba.nvme_cq[qidx], + sli4_hba->sli4_cq_release(sli4_hba->nvme_cq[qidx], LPFC_QUEUE_REARM); if (phba->cfg_fof) - lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM); + sli4_hba->sli4_cq_release(sli4_hba->oas_cq, LPFC_QUEUE_REARM); - if (phba->sli4_hba.hba_eq) + if (sli4_hba->hba_eq) for (qidx = 0; qidx < phba->io_channel_irqs; qidx++) - lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[qidx], - LPFC_QUEUE_REARM); + sli4_hba->sli4_eq_release(sli4_hba->hba_eq[qidx], + LPFC_QUEUE_REARM); if (phba->nvmet_support) { for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) { - lpfc_sli4_cq_release( - phba->sli4_hba.nvmet_cqset[qidx], + sli4_hba->sli4_cq_release( + sli4_hba->nvmet_cqset[qidx], LPFC_QUEUE_REARM); } } if (phba->cfg_fof) - lpfc_sli4_eq_release(phba->sli4_hba.fof_eq, LPFC_QUEUE_REARM); + sli4_hba->sli4_eq_release(sli4_hba->fof_eq, LPFC_QUEUE_REARM); } /** @@ -6533,9 +6716,11 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, struct lpfc_rqe hrqe; struct lpfc_rqe drqe; struct lpfc_rqb *rqbp; + unsigned long flags; struct rqb_dmabuf *rqb_buffer; LIST_HEAD(rqb_buf_list); + spin_lock_irqsave(&phba->hbalock, flags); rqbp = hrq->rqbp; for (i = 0; i < count; i++) { /* IF RQ is already full, don't bother */ @@ -6559,6 +6744,15 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys); rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe); if (rc < 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "6421 Cannot post to HRQ %d: %x %x %x " + "DRQ %x %x\n", + hrq->queue_id, + hrq->host_index, + hrq->hba_index, + hrq->entry_count, + drq->host_index, + drq->hba_index); rqbp->rqb_free_buffer(phba, rqb_buffer); } else { list_add_tail(&rqb_buffer->hbuf.list, @@ -6566,6 +6760,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, rqbp->buffer_count++; } } + spin_unlock_irqrestore(&phba->hbalock, flags); return 1; } @@ -6693,6 +6888,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Save information as VPD data */ phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev; phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev; + + /* + * This is because first G7 ASIC doesn't support the standard + * 0x5a NVME cmd descriptor type/subtype + */ + if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_6) && + (phba->vpd.rev.biuRev == LPFC_G7_ASIC_1) && + (phba->vpd.rev.smRev == 0) && + (phba->cfg_nvme_embed_cmd == 1)) + phba->cfg_nvme_embed_cmd = 0; + phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev; phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high, &mqe->un.read_rev); @@ -6771,21 +6978,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "0378 No support for fcpi mode.\n"); ftr_rsp++; } - if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs)) - phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED; - else - phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED; + + /* Performance Hints are ONLY for FCoE */ + if (phba->hba_flag & HBA_FCOE_MODE) { + if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs)) + phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED; + else + phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED; + } + /* * If the port cannot support the host's requested features * then turn off the global config parameters to disable the * feature in the driver. This is not a fatal error. */ - phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; - if (phba->cfg_enable_bg) { - if (bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)) - phba->sli3_options |= LPFC_SLI3_BG_ENABLED; - else + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { + if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) { + phba->cfg_enable_bg = 0; + phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; ftr_rsp++; + } } if (phba->max_vpi && phba->cfg_enable_npiv && @@ -7209,6 +7421,7 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) struct lpfc_queue *mcq; struct lpfc_mcqe *mcqe; bool pending_completions = false; + uint8_t qe_valid; if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4)) return false; @@ -7217,7 +7430,8 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) mcq = phba->sli4_hba.mbx_cq; idx = mcq->hba_index; - while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe)) { + qe_valid = mcq->qe_valid; + while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe) == qe_valid) { mcqe = (struct lpfc_mcqe *)mcq->qe[idx].cqe; if (bf_get_le32(lpfc_trailer_completed, mcqe) && (!bf_get_le32(lpfc_trailer_async, mcqe))) { @@ -7227,6 +7441,10 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) idx = (idx + 1) % mcq->entry_count; if (mcq->hba_index == idx) break; + + /* if the index wrapped around, toggle the valid bit */ + if (phba->sli4_hba.pc_sli4_params.cqav && !idx) + qe_valid = (qe_valid) ? 0 : 1; } return pending_completions; @@ -7246,7 +7464,7 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) { - + struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba; uint32_t eqidx; struct lpfc_queue *fpeq = NULL; struct lpfc_eqe *eqe; @@ -7257,11 +7475,11 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) /* Find the eq associated with the mcq */ - if (phba->sli4_hba.hba_eq) + if (sli4_hba->hba_eq) for (eqidx = 0; eqidx < phba->io_channel_irqs; eqidx++) - if (phba->sli4_hba.hba_eq[eqidx]->queue_id == - phba->sli4_hba.mbx_cq->assoc_qid) { - fpeq = phba->sli4_hba.hba_eq[eqidx]; + if (sli4_hba->hba_eq[eqidx]->queue_id == + sli4_hba->mbx_cq->assoc_qid) { + fpeq = sli4_hba->hba_eq[eqidx]; break; } if (!fpeq) @@ -7269,7 +7487,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) /* Turn off interrupts from this EQ */ - lpfc_sli4_eq_clr_intr(fpeq); + sli4_hba->sli4_eq_clr_intr(fpeq); /* Check to see if a mbox completion is pending */ @@ -7290,7 +7508,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) /* Always clear and re-arm the EQ */ - lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); + sli4_hba->sli4_eq_release(fpeq, LPFC_QUEUE_REARM); return mbox_pending; @@ -8100,7 +8318,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, } else if (flag == MBX_POLL) { lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, "(%d):2542 Try to issue mailbox command " - "x%x (x%x/x%x) synchronously ahead of async" + "x%x (x%x/x%x) synchronously ahead of async " "mailbox command queue: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, @@ -8664,7 +8882,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, **/ static int lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, - union lpfc_wqe *wqe) + union lpfc_wqe128 *wqe) { uint32_t xmit_len = 0, total_len = 0; uint8_t ct = 0; @@ -8767,7 +8985,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->context2)->virt); if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || *pcmd == ELS_CMD_FDISC || @@ -8870,31 +9088,36 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, } /* Note, word 10 is already initialized to 0 */ + /* Don't set PBDE for Perf hints, just fcp_embed_pbde */ + if (phba->fcp_embed_pbde) + bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1); + else + bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); + if (phba->fcp_embed_io) { struct lpfc_scsi_buf *lpfc_cmd; struct sli4_sge *sgl; - union lpfc_wqe128 *wqe128; struct fcp_cmnd *fcp_cmnd; uint32_t *ptr; /* 128 byte wqe support here */ - wqe128 = (union lpfc_wqe128 *)wqe; lpfc_cmd = iocbq->context1; sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; fcp_cmnd = lpfc_cmd->fcp_cmnd; /* Word 0-2 - FCP_CMND */ - wqe128->generic.bde.tus.f.bdeFlags = + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED; - wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len; - wqe128->generic.bde.addrHigh = 0; - wqe128->generic.bde.addrLow = 88; /* Word 22 */ + wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 88; /* Word 22 */ - bf_set(wqe_wqes, &wqe128->fcp_iwrite.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); /* Word 22-29 FCP CMND Payload */ - ptr = &wqe128->words[22]; + ptr = &wqe->words[22]; memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); } break; @@ -8929,31 +9152,36 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, } /* Note, word 10 is already initialized to 0 */ + /* Don't set PBDE for Perf hints, just fcp_embed_pbde */ + if (phba->fcp_embed_pbde) + bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1); + else + bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0); + if (phba->fcp_embed_io) { struct lpfc_scsi_buf *lpfc_cmd; struct sli4_sge *sgl; - union lpfc_wqe128 *wqe128; struct fcp_cmnd *fcp_cmnd; uint32_t *ptr; /* 128 byte wqe support here */ - wqe128 = (union lpfc_wqe128 *)wqe; lpfc_cmd = iocbq->context1; sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; fcp_cmnd = lpfc_cmd->fcp_cmnd; /* Word 0-2 - FCP_CMND */ - wqe128->generic.bde.tus.f.bdeFlags = + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED; - wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len; - wqe128->generic.bde.addrHigh = 0; - wqe128->generic.bde.addrLow = 88; /* Word 22 */ + wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 88; /* Word 22 */ - bf_set(wqe_wqes, &wqe128->fcp_iread.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); /* Word 22-29 FCP CMND Payload */ - ptr = &wqe128->words[22]; + ptr = &wqe->words[22]; memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); } break; @@ -8990,28 +9218,27 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (phba->fcp_embed_io) { struct lpfc_scsi_buf *lpfc_cmd; struct sli4_sge *sgl; - union lpfc_wqe128 *wqe128; struct fcp_cmnd *fcp_cmnd; uint32_t *ptr; /* 128 byte wqe support here */ - wqe128 = (union lpfc_wqe128 *)wqe; lpfc_cmd = iocbq->context1; sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; fcp_cmnd = lpfc_cmd->fcp_cmnd; /* Word 0-2 - FCP_CMND */ - wqe128->generic.bde.tus.f.bdeFlags = + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED; - wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len; - wqe128->generic.bde.addrHigh = 0; - wqe128->generic.bde.addrLow = 88; /* Word 22 */ + wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 88; /* Word 22 */ - bf_set(wqe_wqes, &wqe128->fcp_icmd.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); /* Word 22-29 FCP CMND Payload */ - ptr = &wqe128->words[22]; + ptr = &wqe->words[22]; memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); } break; @@ -9064,7 +9291,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { if (iocbq->vport->fc_flag & FC_PT2PT) { bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, @@ -9249,8 +9476,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { struct lpfc_sglq *sglq; - union lpfc_wqe *wqe; - union lpfc_wqe128 wqe128; + union lpfc_wqe128 wqe; struct lpfc_queue *wq; struct lpfc_sli_ring *pring; @@ -9270,9 +9496,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, /* * The WQE can be either 64 or 128 bytes, - * so allocate space on the stack assuming the largest. */ - wqe = (union lpfc_wqe *)&wqe128; lockdep_assert_held(&phba->hbalock); @@ -9322,10 +9546,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return IOCB_ERROR; } - if (lpfc_sli4_iocb2wqe(phba, piocb, wqe)) + if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) return IOCB_ERROR; - if (lpfc_sli4_wq_put(wq, wqe)) + if (lpfc_sli4_wq_put(wq, &wqe)) return IOCB_ERROR; lpfc_sli_ringtxcmpl_put(phba, pring, piocb); @@ -9470,7 +9694,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, fpeq = phba->sli4_hba.hba_eq[idx]; /* Turn off interrupts from this EQ */ - lpfc_sli4_eq_clr_intr(fpeq); + phba->sli4_hba.sli4_eq_clr_intr(fpeq); /* * Process all the events on FCP EQ @@ -9482,7 +9706,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, } /* Always clear and re-arm the EQ */ - lpfc_sli4_eq_release(fpeq, + phba->sli4_hba.sli4_eq_release(fpeq, LPFC_QUEUE_REARM); } atomic_inc(&hba_eq_hdl->hba_eq_in_use); @@ -10695,7 +10919,7 @@ lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, { struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_iocbq *abtsiocbp; - union lpfc_wqe *abts_wqe; + union lpfc_wqe128 *abts_wqe; int retval; /* @@ -11442,31 +11666,25 @@ int lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, uint32_t timeout) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); - MAILBOX_t *mb = NULL; + struct completion mbox_done; int retval; unsigned long flag; - /* The caller might set context1 for extended buffer */ - if (pmboxq->context1) - mb = (MAILBOX_t *)pmboxq->context1; - pmboxq->mbox_flag &= ~LPFC_MBX_WAKE; /* setup wake call as IOCB callback */ pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait; - /* setup context field to pass wait_queue pointer to wake function */ - pmboxq->context1 = &done_q; + /* setup context3 field to pass wait_queue pointer to wake function */ + init_completion(&mbox_done); + pmboxq->context3 = &mbox_done; /* now issue the command */ retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); if (retval == MBX_BUSY || retval == MBX_SUCCESS) { - wait_event_interruptible_timeout(done_q, - pmboxq->mbox_flag & LPFC_MBX_WAKE, - msecs_to_jiffies(timeout * 1000)); + wait_for_completion_timeout(&mbox_done, + msecs_to_jiffies(timeout * 1000)); spin_lock_irqsave(&phba->hbalock, flag); - /* restore the possible extended buffer for free resource */ - pmboxq->context1 = (uint8_t *)mb; + pmboxq->context3 = NULL; /* * if LPFC_MBX_WAKE flag is set the mailbox is completed * else do not free the resources. @@ -11478,11 +11696,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } spin_unlock_irqrestore(&phba->hbalock, flag); - } else { - /* restore the possible extended buffer for free resource */ - pmboxq->context1 = (uint8_t *)mb; } - return retval; } @@ -11648,6 +11862,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) } break; case LPFC_SLI_INTF_IF_TYPE_2: + case LPFC_SLI_INTF_IF_TYPE_6: if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, &portstat_reg.word0) || lpfc_readl(phba->sli4_hba.PSMPHRregaddr, @@ -13112,7 +13327,7 @@ lpfc_sli4_sp_process_cq(struct work_struct *work) "(x%x), type (%d)\n", cq->queue_id, cq->type); /* In any case, flash and re-arm the RCQ */ - lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_cq_release(cq, LPFC_QUEUE_REARM); /* wake up worker thread if there are works to be done */ if (workposted) @@ -13230,6 +13445,8 @@ lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, if (childwq->queue_id == hba_wqid) { lpfc_sli4_wq_release(childwq, bf_get(lpfc_wcqe_r_wqe_index, wcqe)); + if (childwq->q_flag & HBA_NVMET_WQFULL) + lpfc_nvmet_wqfull_process(phba, childwq); wqid_matched = true; break; } @@ -13542,7 +13759,7 @@ lpfc_sli4_hba_process_cq(struct work_struct *work) "queue fcpcqid=%d\n", cq->queue_id); /* In any case, flash and re-arm the CQ */ - lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_cq_release(cq, LPFC_QUEUE_REARM); /* wake up worker thread if there are works to be done */ if (workposted) @@ -13559,7 +13776,7 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) ; /* Clear and re-arm the EQ */ - lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_eq_release(eq, LPFC_QUEUE_REARM); } @@ -13707,7 +13924,7 @@ lpfc_sli4_fof_intr_handler(int irq, void *dev_id) } } /* Always clear and re-arm the fast-path EQ */ - lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_eq_release(eq, LPFC_QUEUE_REARM); return IRQ_HANDLED; } @@ -13765,7 +13982,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) if (lpfc_fcp_look_ahead) { if (atomic_dec_and_test(&hba_eq_hdl->hba_eq_in_use)) - lpfc_sli4_eq_clr_intr(fpeq); + phba->sli4_hba.sli4_eq_clr_intr(fpeq); else { atomic_inc(&hba_eq_hdl->hba_eq_in_use); return IRQ_NONE; @@ -13800,7 +14017,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) fpeq->EQ_max_eqe = ecount; /* Always clear and re-arm the fast-path EQ */ - lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_eq_release(fpeq, LPFC_QUEUE_REARM); if (unlikely(ecount == 0)) { fpeq->EQ_no_entry++; @@ -13948,6 +14165,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, INIT_LIST_HEAD(&queue->list); INIT_LIST_HEAD(&queue->wq_list); + INIT_LIST_HEAD(&queue->wqfull_list); INIT_LIST_HEAD(&queue->page_list); INIT_LIST_HEAD(&queue->child_list); @@ -14173,11 +14391,21 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) LPFC_MBOX_OPCODE_EQ_CREATE, length, LPFC_SLI4_MBX_EMBED); eq_create = &mbox->u.mqe.un.eq_create; + shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr; bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request, eq->page_count); bf_set(lpfc_eq_context_size, &eq_create->u.request.context, LPFC_EQE_SIZE); bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1); + + /* Use version 2 of CREATE_EQ if eqav is set */ + if (phba->sli4_hba.pc_sli4_params.eqav) { + bf_set(lpfc_mbox_hdr_version, &shdr->request, + LPFC_Q_CREATE_VERSION_2); + bf_set(lpfc_eq_context_autovalid, &eq_create->u.request.context, + phba->sli4_hba.pc_sli4_params.eqav); + } + /* don't setup delay multiplier using EQ_CREATE */ dmult = 0; bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context, @@ -14222,7 +14450,6 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->context1 = NULL; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { @@ -14305,6 +14532,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, (cq->page_size / SLI4_PAGE_SIZE)); bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, eq->queue_id); + bf_set(lpfc_cq_context_autovalid, &cq_create->u.request.context, + phba->sli4_hba.pc_sli4_params.cqav); } else { bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, eq->queue_id); @@ -14476,6 +14705,9 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, &cq_set->u.request, 0); bf_set(lpfc_mbx_cq_create_set_num_cq, &cq_set->u.request, numcq); + bf_set(lpfc_mbx_cq_create_set_autovalid, + &cq_set->u.request, + phba->sli4_hba.pc_sli4_params.cqav); switch (cq->entry_count) { case 2048: case 4096: @@ -14881,6 +15113,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, void __iomem *bar_memmap_p; uint32_t db_offset; uint16_t pci_barset; + uint8_t dpp_barset; + uint32_t dpp_offset; + unsigned long pg_addr; uint8_t wq_create_version; /* sanity check on queue memory */ @@ -14908,43 +15143,19 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bf_set(lpfc_mbox_hdr_version, &shdr->request, phba->sli4_hba.pc_sli4_params.wqv); + if ((phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) || + (wq->page_size > SLI4_PAGE_SIZE)) + wq_create_version = LPFC_Q_CREATE_VERSION_1; + else + wq_create_version = LPFC_Q_CREATE_VERSION_0; + + if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) wq_create_version = LPFC_Q_CREATE_VERSION_1; else wq_create_version = LPFC_Q_CREATE_VERSION_0; switch (wq_create_version) { - case LPFC_Q_CREATE_VERSION_0: - switch (wq->entry_size) { - default: - case 64: - /* Nothing to do, version 0 ONLY supports 64 byte */ - page = wq_create->u.request.page; - break; - case 128: - if (!(phba->sli4_hba.pc_sli4_params.wqsize & - LPFC_WQ_SZ128_SUPPORT)) { - status = -ERANGE; - goto out; - } - /* If we get here the HBA MUST also support V1 and - * we MUST use it - */ - bf_set(lpfc_mbox_hdr_version, &shdr->request, - LPFC_Q_CREATE_VERSION_1); - - bf_set(lpfc_mbx_wq_create_wqe_count, - &wq_create->u.request_1, wq->entry_count); - bf_set(lpfc_mbx_wq_create_wqe_size, - &wq_create->u.request_1, - LPFC_WQ_WQE_SIZE_128); - bf_set(lpfc_mbx_wq_create_page_size, - &wq_create->u.request_1, - LPFC_WQ_PAGE_SIZE_4096); - page = wq_create->u.request_1.page; - break; - } - break; case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, wq->entry_count); @@ -14959,24 +15170,21 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, LPFC_WQ_WQE_SIZE_64); break; case 128: - if (!(phba->sli4_hba.pc_sli4_params.wqsize & - LPFC_WQ_SZ128_SUPPORT)) { - status = -ERANGE; - goto out; - } bf_set(lpfc_mbx_wq_create_wqe_size, &wq_create->u.request_1, LPFC_WQ_WQE_SIZE_128); break; } + /* Request DPP by default */ + bf_set(lpfc_mbx_wq_create_dpp_req, &wq_create->u.request_1, 1); bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, (wq->page_size / SLI4_PAGE_SIZE)); page = wq_create->u.request_1.page; break; default: - status = -ERANGE; - goto out; + page = wq_create->u.request.page; + break; } list_for_each_entry(dmabuf, &wq->page_list, list) { @@ -15000,52 +15208,120 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, status = -ENXIO; goto out; } - wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response); + + if (wq_create_version == LPFC_Q_CREATE_VERSION_0) + wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, + &wq_create->u.response); + else + wq->queue_id = bf_get(lpfc_mbx_wq_create_v1_q_id, + &wq_create->u.response_1); + if (wq->queue_id == 0xFFFF) { status = -ENXIO; goto out; } - if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) { - wq->db_format = bf_get(lpfc_mbx_wq_create_db_format, - &wq_create->u.response); - if ((wq->db_format != LPFC_DB_LIST_FORMAT) && - (wq->db_format != LPFC_DB_RING_FORMAT)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3265 WQ[%d] doorbell format not " - "supported: x%x\n", wq->queue_id, - wq->db_format); - status = -EINVAL; - goto out; - } - pci_barset = bf_get(lpfc_mbx_wq_create_bar_set, - &wq_create->u.response); - bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); - if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3263 WQ[%d] failed to memmap pci " - "barset:x%x\n", wq->queue_id, - pci_barset); - status = -ENOMEM; - goto out; - } - db_offset = wq_create->u.response.doorbell_offset; - if ((db_offset != LPFC_ULP0_WQ_DOORBELL) && - (db_offset != LPFC_ULP1_WQ_DOORBELL)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3252 WQ[%d] doorbell offset not " - "supported: x%x\n", wq->queue_id, - db_offset); - status = -EINVAL; - goto out; - } - wq->db_regaddr = bar_memmap_p + db_offset; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3264 WQ[%d]: barset:x%x, offset:x%x, " - "format:x%x\n", wq->queue_id, pci_barset, - db_offset, wq->db_format); + + wq->db_format = LPFC_DB_LIST_FORMAT; + if (wq_create_version == LPFC_Q_CREATE_VERSION_0) { + if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) { + wq->db_format = bf_get(lpfc_mbx_wq_create_db_format, + &wq_create->u.response); + if ((wq->db_format != LPFC_DB_LIST_FORMAT) && + (wq->db_format != LPFC_DB_RING_FORMAT)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3265 WQ[%d] doorbell format " + "not supported: x%x\n", + wq->queue_id, wq->db_format); + status = -EINVAL; + goto out; + } + pci_barset = bf_get(lpfc_mbx_wq_create_bar_set, + &wq_create->u.response); + bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, + pci_barset); + if (!bar_memmap_p) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3263 WQ[%d] failed to memmap " + "pci barset:x%x\n", + wq->queue_id, pci_barset); + status = -ENOMEM; + goto out; + } + db_offset = wq_create->u.response.doorbell_offset; + if ((db_offset != LPFC_ULP0_WQ_DOORBELL) && + (db_offset != LPFC_ULP1_WQ_DOORBELL)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3252 WQ[%d] doorbell offset " + "not supported: x%x\n", + wq->queue_id, db_offset); + status = -EINVAL; + goto out; + } + wq->db_regaddr = bar_memmap_p + db_offset; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3264 WQ[%d]: barset:x%x, offset:x%x, " + "format:x%x\n", wq->queue_id, + pci_barset, db_offset, wq->db_format); + } else + wq->db_regaddr = phba->sli4_hba.WQDBregaddr; } else { - wq->db_format = LPFC_DB_LIST_FORMAT; - wq->db_regaddr = phba->sli4_hba.WQDBregaddr; + /* Check if DPP was honored by the firmware */ + wq->dpp_enable = bf_get(lpfc_mbx_wq_create_dpp_rsp, + &wq_create->u.response_1); + if (wq->dpp_enable) { + pci_barset = bf_get(lpfc_mbx_wq_create_v1_bar_set, + &wq_create->u.response_1); + bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, + pci_barset); + if (!bar_memmap_p) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3267 WQ[%d] failed to memmap " + "pci barset:x%x\n", + wq->queue_id, pci_barset); + status = -ENOMEM; + goto out; + } + db_offset = wq_create->u.response_1.doorbell_offset; + wq->db_regaddr = bar_memmap_p + db_offset; + wq->dpp_id = bf_get(lpfc_mbx_wq_create_dpp_id, + &wq_create->u.response_1); + dpp_barset = bf_get(lpfc_mbx_wq_create_dpp_bar, + &wq_create->u.response_1); + bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, + dpp_barset); + if (!bar_memmap_p) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3268 WQ[%d] failed to memmap " + "pci barset:x%x\n", + wq->queue_id, dpp_barset); + status = -ENOMEM; + goto out; + } + dpp_offset = wq_create->u.response_1.dpp_offset; + wq->dpp_regaddr = bar_memmap_p + dpp_offset; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3271 WQ[%d]: barset:x%x, offset:x%x, " + "dpp_id:x%x dpp_barset:x%x " + "dpp_offset:x%x\n", + wq->queue_id, pci_barset, db_offset, + wq->dpp_id, dpp_barset, dpp_offset); + + /* Enable combined writes for DPP aperture */ + pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK; +#ifdef CONFIG_X86 + rc = set_memory_wc(pg_addr, 1); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3272 Cannot setup Combined " + "Write on WQ[%d] - disable DPP\n", + wq->queue_id); + phba->cfg_enable_dpp = 0; + } +#else + phba->cfg_enable_dpp = 0; +#endif + } else + wq->db_regaddr = phba->sli4_hba.WQDBregaddr; } wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL); if (wq->pring == NULL) { @@ -18616,6 +18892,7 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); rc = -ENXIO; + *offset = shdr_add_status; } else *offset += wr_object->u.response.actual_write_length; return rc; @@ -18753,8 +19030,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) unsigned long iflags = 0; char *fail_msg = NULL; struct lpfc_sglq *sglq; - union lpfc_wqe128 wqe128; - union lpfc_wqe *wqe = (union lpfc_wqe *) &wqe128; + union lpfc_wqe128 wqe; uint32_t txq_cnt = 0; pring = lpfc_phba_elsring(phba); @@ -18797,9 +19073,9 @@ lpfc_drain_txq(struct lpfc_hba *phba) piocbq->sli4_xritag = sglq->sli4_xritag; if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) fail_msg = "to convert bpl to sgl"; - else if (lpfc_sli4_iocb2wqe(phba, piocbq, wqe)) + else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe)) fail_msg = "to convert iocb to wqe"; - else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, wqe)) + else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) fail_msg = " - Wq is full"; else lpfc_sli_ringtxcmpl_put(phba, pring, piocbq); @@ -18849,7 +19125,7 @@ lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq, struct ulp_bde64 bde; struct sli4_sge *sgl = NULL; struct lpfc_dmabuf *dmabuf; - union lpfc_wqe *wqe; + union lpfc_wqe128 *wqe; int numBdes = 0; int i = 0; uint32_t offset = 0; /* accumulated offset in the sg request list */ @@ -18958,7 +19234,7 @@ int lpfc_sli4_issue_wqe(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *pwqe) { - union lpfc_wqe *wqe = &pwqe->wqe; + union lpfc_wqe128 *wqe = &pwqe->wqe; struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_queue *wq; struct lpfc_sglq *sglq; diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index a3b1b5145d2b..431754195505 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -61,9 +61,8 @@ struct lpfc_iocbq { struct lpfc_wcqe_complete wcqe_cmpl; /* WQE cmpl */ uint64_t isr_timestamp; - /* Be careful here */ - union lpfc_wqe wqe; /* WQE cmd */ - IOCB_t iocb; /* For IOCB cmd or if we want 128 byte WQE */ + union lpfc_wqe128 wqe; /* SLI-4 */ + IOCB_t iocb; /* SLI-3 */ uint8_t rsvd2; uint8_t priority; /* OAS priority */ @@ -148,6 +147,7 @@ typedef struct lpfcMboxq { struct lpfc_vport *vport;/* virtual port pointer */ void *context1; /* caller context information */ void *context2; /* caller context information */ + void *context3; void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); uint8_t mbox_flag; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 81fb58e59e60..cf64aca82bd0 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -145,6 +145,7 @@ struct lpfc_rqb { struct lpfc_queue { struct list_head list; struct list_head wq_list; + struct list_head wqfull_list; enum lpfc_sli4_queue_type type; enum lpfc_sli4_queue_subtype subtype; struct lpfc_hba *phba; @@ -173,10 +174,16 @@ struct lpfc_queue { #define LPFC_EXPANDED_PAGE_SIZE 16384 #define LPFC_DEFAULT_PAGE_SIZE 4096 uint16_t chann; /* IO channel this queue is associated with */ - uint16_t db_format; + uint8_t db_format; #define LPFC_DB_RING_FORMAT 0x01 #define LPFC_DB_LIST_FORMAT 0x02 + uint8_t q_flag; +#define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */ void __iomem *db_regaddr; + uint16_t dpp_enable; + uint16_t dpp_id; + void __iomem *dpp_regaddr; + /* For q stats */ uint32_t q_cnt_1; uint32_t q_cnt_2; @@ -209,6 +216,7 @@ struct lpfc_queue { struct work_struct spwork; uint64_t isr_timestamp; + uint8_t qe_valid; struct lpfc_queue *assoc_qp; union sli4_qe qe[1]; /* array to index entries (must be last) */ }; @@ -479,12 +487,19 @@ struct lpfc_pc_sli4_params { uint8_t mqv; uint8_t wqv; uint8_t rqv; + uint8_t eqav; + uint8_t cqav; uint8_t wqsize; #define LPFC_WQ_SZ64_SUPPORT 1 #define LPFC_WQ_SZ128_SUPPORT 2 uint8_t wqpcnt; }; +#define LPFC_CQ_4K_PAGE_SZ 0x1 +#define LPFC_CQ_16K_PAGE_SZ 0x4 +#define LPFC_WQ_4K_PAGE_SZ 0x1 +#define LPFC_WQ_16K_PAGE_SZ 0x4 + struct lpfc_iov { uint32_t pf_number; uint32_t vf_number; @@ -516,11 +531,17 @@ struct lpfc_vector_map_info { /* SLI4 HBA data structure entries */ struct lpfc_sli4_hba { void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for - PCI BAR0, config space registers */ + * config space registers + */ void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for - PCI BAR1, control registers */ + * control registers + */ void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for - PCI BAR2, doorbell registers */ + * doorbell registers + */ + void __iomem *dpp_regs_memmap_p; /* Kernel memory mapped address for + * dpp registers + */ union { struct { /* IF Type 0, BAR 0 PCI cfg space reg mem map */ @@ -561,7 +582,8 @@ struct lpfc_sli4_hba { /* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */ void __iomem *RQDBregaddr; /* RQ_DOORBELL register */ void __iomem *WQDBregaddr; /* WQ_DOORBELL register */ - void __iomem *EQCQDBregaddr; /* EQCQ_DOORBELL register */ + void __iomem *CQDBregaddr; /* CQ_DOORBELL register */ + void __iomem *EQDBregaddr; /* EQ_DOORBELL register */ void __iomem *MQDBregaddr; /* MQ_DOORBELL register */ void __iomem *BMBXregaddr; /* BootStrap MBX register */ @@ -574,6 +596,10 @@ struct lpfc_sli4_hba { struct lpfc_bbscn_params bbscn_params; struct lpfc_hba_eq_hdl *hba_eq_hdl; /* HBA per-WQ handle */ + void (*sli4_eq_clr_intr)(struct lpfc_queue *q); + uint32_t (*sli4_eq_release)(struct lpfc_queue *q, bool arm); + uint32_t (*sli4_cq_release)(struct lpfc_queue *q, bool arm); + /* Pointers to the constructed SLI4 queues */ struct lpfc_queue **hba_eq; /* Event queues for HBA */ struct lpfc_queue **fcp_cq; /* Fast-path FCP compl queue */ @@ -840,8 +866,12 @@ void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *); int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *); int lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba); int lpfc_sli4_init_vpi(struct lpfc_vport *); +inline void lpfc_sli4_eq_clr_intr(struct lpfc_queue *); uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool); uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool); +inline void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q); +uint32_t lpfc_sli4_if6_cq_release(struct lpfc_queue *q, bool arm); +uint32_t lpfc_sli4_if6_eq_release(struct lpfc_queue *q, bool arm); void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t); int lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *, uint16_t); int lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *, uint16_t); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index c232bf0e8998..e8b089abbfb3 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "11.4.0.6" +#define LPFC_DRIVER_VERSION "12.0.0.1" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ @@ -32,6 +32,6 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright (C) 2017 Broadcom. All Rights Reserved. " \ - "The term \"Broadcom\" refers to Broadcom Limited " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2018 Broadcom. All Rights " \ + "Reserved. The term \"Broadcom\" refers to Broadcom Limited " \ "and/or its subsidiaries." diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 7a37ace4239b..b89c6e6c0589 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4022,7 +4022,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) cmd = instance->cmd_list[i]; - cmd->frame = dma_pool_alloc(instance->frame_dma_pool, + cmd->frame = dma_pool_zalloc(instance->frame_dma_pool, GFP_KERNEL, &cmd->frame_phys_addr); cmd->sense = dma_pool_alloc(instance->sense_dma_pool, @@ -4038,7 +4038,6 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) return -ENOMEM; } - memset(cmd->frame, 0, instance->mfi_frame_size); cmd->frame->io.context = cpu_to_le32(cmd->index); cmd->frame->io.pad_0 = 0; if ((instance->adapter_type == MFI_SERIES) && reset_devices) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index ee117106d0f7..0ad88deb3176 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -524,6 +524,7 @@ typedef struct _MPI2_CONFIG_REPLY { #define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) #define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) #define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) +#define MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP (0x02B0) /*MPI v2.5 SAS products */ #define MPI25_MFGPAGE_DEVID_SAS3004 (0x0096) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 0aafbfd1b746..61f93a134956 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -126,6 +126,362 @@ module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug, param_get_int, &mpt3sas_fwfault_debug, 0644); /** + * _base_clone_reply_to_sys_mem - copies reply to reply free iomem + * in BAR0 space. + * + * @ioc: per adapter object + * @reply: reply message frame(lower 32bit addr) + * @index: System request message index. + * + * @Returns - Nothing + */ +static void +_base_clone_reply_to_sys_mem(struct MPT3SAS_ADAPTER *ioc, u32 reply, + u32 index) +{ + /* + * 256 is offset within sys register. + * 256 offset MPI frame starts. Max MPI frame supported is 32. + * 32 * 128 = 4K. From here, Clone of reply free for mcpu starts + */ + u16 cmd_credit = ioc->facts.RequestCredit + 1; + void __iomem *reply_free_iomem = (void __iomem *)ioc->chip + + MPI_FRAME_START_OFFSET + + (cmd_credit * ioc->request_sz) + (index * sizeof(u32)); + + writel(reply, reply_free_iomem); +} + +/** + * _base_clone_mpi_to_sys_mem - Writes/copies MPI frames + * to system/BAR0 region. + * + * @dst_iomem: Pointer to the destinaltion location in BAR0 space. + * @src: Pointer to the Source data. + * @size: Size of data to be copied. + */ +static void +_base_clone_mpi_to_sys_mem(void *dst_iomem, void *src, u32 size) +{ + int i; + u32 *src_virt_mem = (u32 *)src; + + for (i = 0; i < size/4; i++) + writel((u32)src_virt_mem[i], + (void __iomem *)dst_iomem + (i * 4)); +} + +/** + * _base_clone_to_sys_mem - Writes/copies data to system/BAR0 region + * + * @dst_iomem: Pointer to the destination location in BAR0 space. + * @src: Pointer to the Source data. + * @size: Size of data to be copied. + */ +static void +_base_clone_to_sys_mem(void __iomem *dst_iomem, void *src, u32 size) +{ + int i; + u32 *src_virt_mem = (u32 *)(src); + + for (i = 0; i < size/4; i++) + writel((u32)src_virt_mem[i], + (void __iomem *)dst_iomem + (i * 4)); +} + +/** + * _base_get_chain - Calculates and Returns virtual chain address + * for the provided smid in BAR0 space. + * + * @ioc: per adapter object + * @smid: system request message index + * @sge_chain_count: Scatter gather chain count. + * + * @Return: chain address. + */ +static inline void __iomem* +_base_get_chain(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u8 sge_chain_count) +{ + void __iomem *base_chain, *chain_virt; + u16 cmd_credit = ioc->facts.RequestCredit + 1; + + base_chain = (void __iomem *)ioc->chip + MPI_FRAME_START_OFFSET + + (cmd_credit * ioc->request_sz) + + REPLY_FREE_POOL_SIZE; + chain_virt = base_chain + (smid * ioc->facts.MaxChainDepth * + ioc->request_sz) + (sge_chain_count * ioc->request_sz); + return chain_virt; +} + +/** + * _base_get_chain_phys - Calculates and Returns physical address + * in BAR0 for scatter gather chains, for + * the provided smid. + * + * @ioc: per adapter object + * @smid: system request message index + * @sge_chain_count: Scatter gather chain count. + * + * @Return - Physical chain address. + */ +static inline phys_addr_t +_base_get_chain_phys(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u8 sge_chain_count) +{ + phys_addr_t base_chain_phys, chain_phys; + u16 cmd_credit = ioc->facts.RequestCredit + 1; + + base_chain_phys = ioc->chip_phys + MPI_FRAME_START_OFFSET + + (cmd_credit * ioc->request_sz) + + REPLY_FREE_POOL_SIZE; + chain_phys = base_chain_phys + (smid * ioc->facts.MaxChainDepth * + ioc->request_sz) + (sge_chain_count * ioc->request_sz); + return chain_phys; +} + +/** + * _base_get_buffer_bar0 - Calculates and Returns BAR0 mapped Host + * buffer address for the provided smid. + * (Each smid can have 64K starts from 17024) + * + * @ioc: per adapter object + * @smid: system request message index + * + * @Returns - Pointer to buffer location in BAR0. + */ + +static void __iomem * +_base_get_buffer_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + u16 cmd_credit = ioc->facts.RequestCredit + 1; + // Added extra 1 to reach end of chain. + void __iomem *chain_end = _base_get_chain(ioc, + cmd_credit + 1, + ioc->facts.MaxChainDepth); + return chain_end + (smid * 64 * 1024); +} + +/** + * _base_get_buffer_phys_bar0 - Calculates and Returns BAR0 mapped + * Host buffer Physical address for the provided smid. + * (Each smid can have 64K starts from 17024) + * + * @ioc: per adapter object + * @smid: system request message index + * + * @Returns - Pointer to buffer location in BAR0. + */ +static phys_addr_t +_base_get_buffer_phys_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + u16 cmd_credit = ioc->facts.RequestCredit + 1; + phys_addr_t chain_end_phys = _base_get_chain_phys(ioc, + cmd_credit + 1, + ioc->facts.MaxChainDepth); + return chain_end_phys + (smid * 64 * 1024); +} + +/** + * _base_get_chain_buffer_dma_to_chain_buffer - Iterates chain + * lookup list and Provides chain_buffer + * address for the matching dma address. + * (Each smid can have 64K starts from 17024) + * + * @ioc: per adapter object + * @chain_buffer_dma: Chain buffer dma address. + * + * @Returns - Pointer to chain buffer. Or Null on Failure. + */ +static void * +_base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc, + dma_addr_t chain_buffer_dma) +{ + u16 index; + + for (index = 0; index < ioc->chain_depth; index++) { + if (ioc->chain_lookup[index].chain_buffer_dma == + chain_buffer_dma) + return ioc->chain_lookup[index].chain_buffer; + } + pr_info(MPT3SAS_FMT + "Provided chain_buffer_dma address is not in the lookup list\n", + ioc->name); + return NULL; +} + +/** + * _clone_sg_entries - MPI EP's scsiio and config requests + * are handled here. Base function for + * double buffering, before submitting + * the requests. + * + * @ioc: per adapter object. + * @mpi_request: mf request pointer. + * @smid: system request message index. + * + * @Returns: Nothing. + */ +static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc, + void *mpi_request, u16 smid) +{ + Mpi2SGESimple32_t *sgel, *sgel_next; + u32 sgl_flags, sge_chain_count = 0; + bool is_write = 0; + u16 i = 0; + void __iomem *buffer_iomem; + phys_addr_t buffer_iomem_phys; + void __iomem *buff_ptr; + phys_addr_t buff_ptr_phys; + void __iomem *dst_chain_addr[MCPU_MAX_CHAINS_PER_IO]; + void *src_chain_addr[MCPU_MAX_CHAINS_PER_IO]; + phys_addr_t dst_addr_phys; + MPI2RequestHeader_t *request_hdr; + struct scsi_cmnd *scmd; + struct scatterlist *sg_scmd = NULL; + int is_scsiio_req = 0; + + request_hdr = (MPI2RequestHeader_t *) mpi_request; + + if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) { + Mpi25SCSIIORequest_t *scsiio_request = + (Mpi25SCSIIORequest_t *)mpi_request; + sgel = (Mpi2SGESimple32_t *) &scsiio_request->SGL; + is_scsiio_req = 1; + } else if (request_hdr->Function == MPI2_FUNCTION_CONFIG) { + Mpi2ConfigRequest_t *config_req = + (Mpi2ConfigRequest_t *)mpi_request; + sgel = (Mpi2SGESimple32_t *) &config_req->PageBufferSGE; + } else + return; + + /* From smid we can get scsi_cmd, once we have sg_scmd, + * we just need to get sg_virt and sg_next to get virual + * address associated with sgel->Address. + */ + + if (is_scsiio_req) { + /* Get scsi_cmd using smid */ + scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); + if (scmd == NULL) { + pr_err(MPT3SAS_FMT "scmd is NULL\n", ioc->name); + return; + } + + /* Get sg_scmd from scmd provided */ + sg_scmd = scsi_sglist(scmd); + } + + /* + * 0 - 255 System register + * 256 - 4352 MPI Frame. (This is based on maxCredit 32) + * 4352 - 4864 Reply_free pool (512 byte is reserved + * considering maxCredit 32. Reply need extra + * room, for mCPU case kept four times of + * maxCredit). + * 4864 - 17152 SGE chain element. (32cmd * 3 chain of + * 128 byte size = 12288) + * 17152 - x Host buffer mapped with smid. + * (Each smid can have 64K Max IO.) + * BAR0+Last 1K MSIX Addr and Data + * Total size in use 2113664 bytes of 4MB BAR0 + */ + + buffer_iomem = _base_get_buffer_bar0(ioc, smid); + buffer_iomem_phys = _base_get_buffer_phys_bar0(ioc, smid); + + buff_ptr = buffer_iomem; + buff_ptr_phys = buffer_iomem_phys; + WARN_ON(buff_ptr_phys > U32_MAX); + + if (sgel->FlagsLength & + (MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT)) + is_write = 1; + + for (i = 0; i < MPT_MIN_PHYS_SEGMENTS + ioc->facts.MaxChainDepth; i++) { + + sgl_flags = (sgel->FlagsLength >> MPI2_SGE_FLAGS_SHIFT); + + switch (sgl_flags & MPI2_SGE_FLAGS_ELEMENT_MASK) { + case MPI2_SGE_FLAGS_CHAIN_ELEMENT: + /* + * Helper function which on passing + * chain_buffer_dma returns chain_buffer. Get + * the virtual address for sgel->Address + */ + sgel_next = + _base_get_chain_buffer_dma_to_chain_buffer(ioc, + sgel->Address); + if (sgel_next == NULL) + return; + /* + * This is coping 128 byte chain + * frame (not a host buffer) + */ + dst_chain_addr[sge_chain_count] = + _base_get_chain(ioc, + smid, sge_chain_count); + src_chain_addr[sge_chain_count] = + (void *) sgel_next; + dst_addr_phys = _base_get_chain_phys(ioc, + smid, sge_chain_count); + WARN_ON(dst_addr_phys > U32_MAX); + sgel->Address = (u32)dst_addr_phys; + sgel = sgel_next; + sge_chain_count++; + break; + case MPI2_SGE_FLAGS_SIMPLE_ELEMENT: + if (is_write) { + if (is_scsiio_req) { + _base_clone_to_sys_mem(buff_ptr, + sg_virt(sg_scmd), + (sgel->FlagsLength & 0x00ffffff)); + /* + * FIXME: this relies on a a zero + * PCI mem_offset. + */ + sgel->Address = (u32)buff_ptr_phys; + } else { + _base_clone_to_sys_mem(buff_ptr, + ioc->config_vaddr, + (sgel->FlagsLength & 0x00ffffff)); + sgel->Address = (u32)buff_ptr_phys; + } + } + buff_ptr += (sgel->FlagsLength & 0x00ffffff); + buff_ptr_phys += (sgel->FlagsLength & 0x00ffffff); + if ((sgel->FlagsLength & + (MPI2_SGE_FLAGS_END_OF_BUFFER + << MPI2_SGE_FLAGS_SHIFT))) + goto eob_clone_chain; + else { + /* + * Every single element in MPT will have + * associated sg_next. Better to sanity that + * sg_next is not NULL, but it will be a bug + * if it is null. + */ + if (is_scsiio_req) { + sg_scmd = sg_next(sg_scmd); + if (sg_scmd) + sgel++; + else + goto eob_clone_chain; + } + } + break; + } + } + +eob_clone_chain: + for (i = 0; i < sge_chain_count; i++) { + if (is_scsiio_req) + _base_clone_to_sys_mem(dst_chain_addr[i], + src_chain_addr[i], ioc->request_sz); + } +} + +/** * mpt3sas_remove_dead_ioc_func - kthread context to remove dead ioc * @arg: input argument, used to derive ioc * @@ -875,7 +1231,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) ack_request->EventContext = mpi_reply->EventContext; ack_request->VF_ID = 0; /* TODO */ ack_request->VP_ID = 0; - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); out: @@ -1075,6 +1431,10 @@ _base_interrupt(int irq, void *bus_id) 0 : ioc->reply_free_host_index + 1; ioc->reply_free[ioc->reply_free_host_index] = cpu_to_le32(reply); + if (ioc->is_mcpu_endpoint) + _base_clone_reply_to_sys_mem(ioc, + cpu_to_le32(reply), + ioc->reply_free_host_index); writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); } @@ -2214,6 +2574,9 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) struct sysinfo s; u64 consistent_dma_mask; + if (ioc->is_mcpu_endpoint) + goto try_32bit; + if (ioc->dma_mask) consistent_dma_mask = DMA_BIT_MASK(64); else @@ -2232,6 +2595,7 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) } } + try_32bit: if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { ioc->base_add_sg_single = &_base_add_sg_single_32; @@ -2581,7 +2945,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) u32 pio_sz; int i, r = 0; u64 pio_chip = 0; - u64 chip_phys = 0; + phys_addr_t chip_phys = 0; struct adapter_reply_queue *reply_q; dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", @@ -2629,7 +2993,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (memap_sz) continue; ioc->chip_phys = pci_resource_start(pdev, i); - chip_phys = (u64)ioc->chip_phys; + chip_phys = ioc->chip_phys; memap_sz = pci_resource_len(pdev, i); ioc->chip = ioremap(ioc->chip_phys, memap_sz); } @@ -2704,8 +3068,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) "IO-APIC enabled"), pci_irq_vector(ioc->pdev, reply_q->msix_index)); - pr_info(MPT3SAS_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", - ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); + pr_info(MPT3SAS_FMT "iomem(%pap), mapped(0x%p), size(%d)\n", + ioc->name, &chip_phys, ioc->chip, memap_sz); pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n", ioc->name, (unsigned long long)pio_chip, pio_sz); @@ -2961,6 +3325,29 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** + * _base_mpi_ep_writeq - 32 bit write to MMIO + * @b: data payload + * @addr: address in MMIO space + * @writeq_lock: spin lock + * + * This special handling for MPI EP to take care of 32 bit + * environment where its not quarenteed to send the entire word + * in one transfer. + */ +static inline void +_base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr, + spinlock_t *writeq_lock) +{ + unsigned long flags; + __u64 data_out = cpu_to_le64(b); + + spin_lock_irqsave(writeq_lock, flags); + writel((u32)(data_out), addr); + writel((u32)(data_out >> 32), (addr + 4)); + spin_unlock_irqrestore(writeq_lock, flags); +} + +/** * _base_writeq - 64 bit write to MMIO * @ioc: per adapter object * @b: data payload @@ -2981,17 +3368,41 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) static inline void _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) { - unsigned long flags; - __u64 data_out = cpu_to_le64(b); - - spin_lock_irqsave(writeq_lock, flags); - writel((u32)(data_out), addr); - writel((u32)(data_out >> 32), (addr + 4)); - spin_unlock_irqrestore(writeq_lock, flags); + _base_mpi_ep_writeq(b, addr, writeq_lock); } #endif /** + * _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware + * @ioc: per adapter object + * @smid: system request message index + * @handle: device handle + * + * Return nothing. + */ +static void +_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) +{ + Mpi2RequestDescriptorUnion_t descriptor; + u64 *request = (u64 *)&descriptor; + void *mpi_req_iomem; + __le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid); + + _clone_sg_entries(ioc, (void *) mfp, smid); + mpi_req_iomem = (void *)ioc->chip + + MPI_FRAME_START_OFFSET + (smid * ioc->request_sz); + _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, + ioc->request_sz); + descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SCSIIO.SMID = cpu_to_le16(smid); + descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); + descriptor.SCSIIO.LMID = 0; + _base_mpi_ep_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); +} + +/** * _base_put_smid_scsi_io - send SCSI_IO request to firmware * @ioc: per adapter object * @smid: system request message index @@ -3016,15 +3427,15 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) } /** - * _base_put_smid_fast_path - send fast path request to firmware + * mpt3sas_base_put_smid_fast_path - send fast path request to firmware * @ioc: per adapter object * @smid: system request message index * @handle: device handle * * Return nothing. */ -static void -_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, +void +mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) { Mpi2RequestDescriptorUnion_t descriptor; @@ -3041,18 +3452,34 @@ _base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, } /** - * _base_put_smid_hi_priority - send Task Management request to firmware + * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware * @ioc: per adapter object * @smid: system request message index * @msix_task: msix_task will be same as msix of IO incase of task abort else 0. * Return nothing. */ -static void -_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, +void +mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 msix_task) { Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; + void *mpi_req_iomem; + u64 *request; + + if (ioc->is_mcpu_endpoint) { + MPI2RequestHeader_t *request_hdr; + + __le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid); + + request_hdr = (MPI2RequestHeader_t *)mfp; + /* TBD 256 is offset within sys register. */ + mpi_req_iomem = (void *)ioc->chip + MPI_FRAME_START_OFFSET + + (smid * ioc->request_sz); + _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, + ioc->request_sz); + } + + request = (u64 *)&descriptor; descriptor.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; @@ -3060,20 +3487,25 @@ _base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, descriptor.HighPriority.SMID = cpu_to_le16(smid); descriptor.HighPriority.LMID = 0; descriptor.HighPriority.Reserved1 = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); + if (ioc->is_mcpu_endpoint) + _base_mpi_ep_writeq(*request, + &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); + else + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); } /** - * _base_put_smid_nvme_encap - send NVMe encapsulated request to + * mpt3sas_base_put_smid_nvme_encap - send NVMe encapsulated request to * firmware * @ioc: per adapter object * @smid: system request message index * * Return nothing. */ -static void -_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) +void +mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; @@ -3089,135 +3521,45 @@ _base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** - * _base_put_smid_default - Default, primarily used for config pages + * mpt3sas_base_put_smid_default - Default, primarily used for config pages * @ioc: per adapter object * @smid: system request message index * * Return nothing. */ -static void -_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) +void +mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) { Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; + void *mpi_req_iomem; + u64 *request; + MPI2RequestHeader_t *request_hdr; + + if (ioc->is_mcpu_endpoint) { + __le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid); + request_hdr = (MPI2RequestHeader_t *)mfp; + + _clone_sg_entries(ioc, (void *) mfp, smid); + /* TBD 256 is offset within sys register */ + mpi_req_iomem = (void *)ioc->chip + + MPI_FRAME_START_OFFSET + (smid * ioc->request_sz); + _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, + ioc->request_sz); + } + request = (u64 *)&descriptor; descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** -* _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using -* Atomic Request Descriptor -* @ioc: per adapter object -* @smid: system request message index -* @handle: device handle, unused in this function, for function type match -* -* Return nothing. -*/ -static void -_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, - u16 handle) -{ - Mpi26AtomicRequestDescriptor_t descriptor; - u32 *request = (u32 *)&descriptor; - - descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SMID = cpu_to_le16(smid); - - writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); -} - -/** - * _base_put_smid_fast_path_atomic - send fast path request to firmware - * using Atomic Request Descriptor - * @ioc: per adapter object - * @smid: system request message index - * @handle: device handle, unused in this function, for function type match - * Return nothing - */ -static void -_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, - u16 handle) -{ - Mpi26AtomicRequestDescriptor_t descriptor; - u32 *request = (u32 *)&descriptor; - - descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; - descriptor.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SMID = cpu_to_le16(smid); - - writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); -} - -/** - * _base_put_smid_hi_priority_atomic - send Task Management request to - * firmware using Atomic Request Descriptor - * @ioc: per adapter object - * @smid: system request message index - * @msix_task: msix_task will be same as msix of IO incase of task abort else 0 - * - * Return nothing. - */ -static void -_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, - u16 msix_task) -{ - Mpi26AtomicRequestDescriptor_t descriptor; - u32 *request = (u32 *)&descriptor; - - descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; - descriptor.MSIxIndex = msix_task; - descriptor.SMID = cpu_to_le16(smid); - - writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); -} - -/** - * _base_put_smid_nvme_encap_atomic - send NVMe encapsulated request to - * firmware using Atomic Request Descriptor - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -static void -_base_put_smid_nvme_encap_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) -{ - Mpi26AtomicRequestDescriptor_t descriptor; - u32 *request = (u32 *)&descriptor; - - descriptor.RequestFlags = MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; - descriptor.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SMID = cpu_to_le16(smid); - - writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); -} - -/** - * _base_put_smid_default - Default, primarily used for config pages - * use Atomic Request Descriptor - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -static void -_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) -{ - Mpi26AtomicRequestDescriptor_t descriptor; - u32 *request = (u32 *)&descriptor; - - descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SMID = cpu_to_le16(smid); - - writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); + if (ioc->is_mcpu_endpoint) + _base_mpi_ep_writeq(*request, + &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); + else + _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, + &ioc->scsi_lookup_lock); } /** @@ -3890,17 +4232,21 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) sg_tablesize = min_t(unsigned short, sg_tablesize, MPT_KDUMP_MIN_PHYS_SEGMENTS); - if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) - sg_tablesize = MPT_MIN_PHYS_SEGMENTS; - else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { - sg_tablesize = min_t(unsigned short, sg_tablesize, - SG_MAX_SEGMENTS); - pr_warn(MPT3SAS_FMT - "sg_tablesize(%u) is bigger than kernel" - " defined SG_CHUNK_SIZE(%u)\n", ioc->name, - sg_tablesize, MPT_MAX_PHYS_SEGMENTS); + if (ioc->is_mcpu_endpoint) + ioc->shost->sg_tablesize = MPT_MIN_PHYS_SEGMENTS; + else { + if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) + sg_tablesize = MPT_MIN_PHYS_SEGMENTS; + else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { + sg_tablesize = min_t(unsigned short, sg_tablesize, + SG_MAX_SEGMENTS); + pr_warn(MPT3SAS_FMT + "sg_tablesize(%u) is bigger than kernel " + "defined SG_CHUNK_SIZE(%u)\n", ioc->name, + sg_tablesize, MPT_MAX_PHYS_SEGMENTS); + } + ioc->shost->sg_tablesize = sg_tablesize; } - ioc->shost->sg_tablesize = sg_tablesize; ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)), (facts->RequestCredit / 4)); @@ -3985,13 +4331,18 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) /* reply free queue sizing - taking into account for 64 FW events */ ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - /* calculate reply descriptor post queue depth */ - ioc->reply_post_queue_depth = ioc->hba_queue_depth + - ioc->reply_free_queue_depth + 1 ; - /* align the reply post queue on the next 16 count boundary */ - if (ioc->reply_post_queue_depth % 16) - ioc->reply_post_queue_depth += 16 - - (ioc->reply_post_queue_depth % 16); + /* mCPU manage single counters for simplicity */ + if (ioc->is_mcpu_endpoint) + ioc->reply_post_queue_depth = ioc->reply_free_queue_depth; + else { + /* calculate reply descriptor post queue depth */ + ioc->reply_post_queue_depth = ioc->hba_queue_depth + + ioc->reply_free_queue_depth + 1; + /* align the reply post queue on the next 16 count boundary */ + if (ioc->reply_post_queue_depth % 16) + ioc->reply_post_queue_depth += 16 - + (ioc->reply_post_queue_depth % 16); + } if (ioc->reply_post_queue_depth > facts->MaxReplyDescriptorPostQueueDepth) { @@ -4789,7 +5140,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) ioc->ioc_link_reset_in_progress = 1; init_completion(&ioc->base_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || @@ -4889,7 +5240,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, ioc->base_cmds.smid = smid; memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); init_completion(&ioc->base_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { @@ -5074,8 +5425,6 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices)) ioc->rdpq_array_capable = 1; - if (facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ) - ioc->atomic_desc_capable = 1; facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); facts->IOCRequestFrameSize = le16_to_cpu(mpi_reply.IOCRequestFrameSize); @@ -5317,7 +5666,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; init_completion(&ioc->port_enable_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ); if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) { pr_err(MPT3SAS_FMT "%s: timeout\n", @@ -5380,7 +5729,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc) memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); return 0; } @@ -5499,7 +5848,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc) mpi_request->EventMasks[i] = cpu_to_le32(ioc->event_masks[i]); init_completion(&ioc->base_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { pr_err(MPT3SAS_FMT "%s: timeout\n", @@ -5819,8 +6168,12 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) /* initialize Reply Free Queue */ for (i = 0, reply_address = (u32)ioc->reply_dma ; i < ioc->reply_free_queue_depth ; i++, reply_address += - ioc->reply_sz) + ioc->reply_sz) { ioc->reply_free[i] = cpu_to_le32(reply_address); + if (ioc->is_mcpu_endpoint) + _base_clone_reply_to_sys_mem(ioc, + (__le32)reply_address, i); + } /* initialize reply queues */ if (ioc->is_driver_loading) @@ -6009,20 +6362,10 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) break; } - if (ioc->atomic_desc_capable) { - ioc->put_smid_default = &_base_put_smid_default_atomic; - ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic; - ioc->put_smid_fast_path = &_base_put_smid_fast_path_atomic; - ioc->put_smid_hi_priority = &_base_put_smid_hi_priority_atomic; - ioc->put_smid_nvme_encap = &_base_put_smid_nvme_encap_atomic; - } else { - ioc->put_smid_default = &_base_put_smid_default; + if (ioc->is_mcpu_endpoint) + ioc->put_smid_scsi_io = &_base_put_smid_mpi_ep_scsi_io; + else ioc->put_smid_scsi_io = &_base_put_smid_scsi_io; - ioc->put_smid_fast_path = &_base_put_smid_fast_path; - ioc->put_smid_hi_priority = &_base_put_smid_hi_priority; - ioc->put_smid_nvme_encap = &_base_put_smid_nvme_encap; - } - /* * These function pointers for other requests that don't diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 99ccf83b8c51..ae36d8fb2f2b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -95,6 +95,8 @@ #define MPT_MIN_PHYS_SEGMENTS 16 #define MPT_KDUMP_MIN_PHYS_SEGMENTS 32 +#define MCPU_MAX_CHAINS_PER_IO 3 + #ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE #define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE #else @@ -120,6 +122,8 @@ #define MPT3SAS_NVME_QUEUE_DEPTH 128 #define MPT_NAME_LENGTH 32 /* generic length of strings */ #define MPT_STRING_LENGTH 64 +#define MPI_FRAME_START_OFFSET 256 +#define REPLY_FREE_POOL_SIZE 512 /*(32 maxcredix *4)*(4 times)*/ #define MPT_MAX_CALLBACKS 32 @@ -1099,7 +1103,7 @@ struct MPT3SAS_ADAPTER { char tmp_string[MPT_STRING_LENGTH]; struct pci_dev *pdev; Mpi2SystemInterfaceRegs_t __iomem *chip; - resource_size_t chip_phys; + phys_addr_t chip_phys; int logging_level; int fwfault_debug; u8 ir_firmware; @@ -1236,6 +1240,7 @@ struct MPT3SAS_ADAPTER { u16 config_page_sz; void *config_page; dma_addr_t config_page_dma; + void *config_vaddr; /* scsiio request */ u16 hba_queue_depth; @@ -1336,6 +1341,7 @@ struct MPT3SAS_ADAPTER { u32 ring_buffer_offset; u32 ring_buffer_sz; u8 is_warpdrive; + u8 is_mcpu_endpoint; u8 hide_ir_msg; u8 mfg_pg10_hide_flag; u8 hide_drives; @@ -1348,12 +1354,7 @@ struct MPT3SAS_ADAPTER { void *device_remove_in_progress; u16 device_remove_in_progress_sz; u8 is_gen35_ioc; - u8 atomic_desc_capable; PUT_SMID_IO_FP_HIP put_smid_scsi_io; - PUT_SMID_IO_FP_HIP put_smid_fast_path; - PUT_SMID_IO_FP_HIP put_smid_hi_priority; - PUT_SMID_DEFAULT put_smid_default; - PUT_SMID_DEFAULT put_smid_nvme_encap; }; @@ -1394,6 +1395,12 @@ void *mpt3sas_base_get_pcie_sgl(struct MPT3SAS_ADAPTER *ioc, u16 smid); dma_addr_t mpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid); void mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc); +void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 handle); +void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 msix_task); +void mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid); /* hi-priority queue */ u16 mpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); u16 mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index 1c747cf419d5..e87c76a832f6 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -219,6 +219,7 @@ _config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc, mem->page = ioc->config_page; mem->page_dma = ioc->config_page_dma; } + ioc->config_vaddr = mem->page; return r; } @@ -402,7 +403,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); _config_display_some_debug(ioc, smid, "config_request", NULL); init_completion(&ioc->config_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ); if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) { pr_err(MPT3SAS_FMT "%s: timeout\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 523971aeb4c1..d3cb387ba9f4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -820,7 +820,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, ret = -EINVAL; goto out; } - ioc->put_smid_nvme_encap(ioc, smid); + mpt3sas_base_put_smid_nvme_encap(ioc, smid); break; } case MPI2_FUNCTION_SCSI_IO_REQUEST: @@ -845,7 +845,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) ioc->put_smid_scsi_io(ioc, smid, device_handle); else - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -882,7 +882,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, tm_request->DevHandle)); ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - ioc->put_smid_hi_priority(ioc, smid, 0); + mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); break; } case MPI2_FUNCTION_SMP_PASSTHROUGH: @@ -913,7 +913,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, } ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SATA_PASSTHROUGH: @@ -928,7 +928,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, } ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_FW_DOWNLOAD: @@ -936,7 +936,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, { ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_TOOLBOX: @@ -951,7 +951,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); } - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: @@ -970,7 +970,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, default: ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); break; } @@ -1601,7 +1601,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, cpu_to_le32(ioc->product_specific[buffer_type][i]); init_completion(&ioc->ctl_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1948,7 +1948,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, mpi_request->VP_ID = 0; init_completion(&ioc->ctl_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2215,7 +2215,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) mpi_request->VP_ID = 0; init_completion(&ioc->ctl_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index aee1a0e1c600..8cd3782fab49 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2679,7 +2679,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); mpt3sas_scsih_set_tm_flag(ioc, handle); init_completion(&ioc->tm_cmds.done); - ioc->put_smid_hi_priority(ioc, smid, msix_task); + mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task); wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) { pr_err(MPT3SAS_FMT "%s: timeout\n", @@ -3641,7 +3641,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; set_bit(handle, ioc->device_remove_in_progress); - ioc->put_smid_hi_priority(ioc, smid, 0); + mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); out: @@ -3742,7 +3742,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; mpi_request->DevHandle = mpi_request_tm->DevHandle; - ioc->put_smid_default(ioc, smid_sas_ctrl); + mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl); return _scsih_check_for_pending_tm(ioc, smid); } @@ -3837,7 +3837,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - ioc->put_smid_hi_priority(ioc, smid, 0); + mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); } /** @@ -3929,7 +3929,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event, ack_request->EventContext = event_context; ack_request->VF_ID = 0; /* TODO */ ack_request->VP_ID = 0; - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); } /** @@ -3986,7 +3986,7 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc, mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; mpi_request->DevHandle = handle; - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); } /** @@ -4715,12 +4715,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len | MPI25_SCSIIO_IOFLAGS_FAST_PATH); - ioc->put_smid_fast_path(ioc, smid, handle); + mpt3sas_base_put_smid_fast_path(ioc, smid, handle); } else ioc->put_smid_scsi_io(ioc, smid, le16_to_cpu(mpi_request->DevHandle)); } else - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); return 0; out: @@ -7609,7 +7609,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) handle, phys_disk_num)); init_completion(&ioc->scsih_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { @@ -9700,7 +9700,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) if (!ioc->hide_ir_msg) pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); init_completion(&ioc->scsih_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { @@ -10346,6 +10346,7 @@ _scsih_determine_hba_mpi_version(struct pci_dev *pdev) case MPI2_MFGPAGE_DEVID_SAS2308_1: case MPI2_MFGPAGE_DEVID_SAS2308_2: case MPI2_MFGPAGE_DEVID_SAS2308_3: + case MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP: return MPI2_VERSION; case MPI25_MFGPAGE_DEVID_SAS3004: case MPI25_MFGPAGE_DEVID_SAS3008: @@ -10423,11 +10424,18 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->hba_mpi_version_belonged = hba_mpi_version; ioc->id = mpt2_ids++; sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME); - if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) { + switch (pdev->device) { + case MPI2_MFGPAGE_DEVID_SSS6200: ioc->is_warpdrive = 1; ioc->hide_ir_msg = 1; - } else + break; + case MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP: + ioc->is_mcpu_endpoint = 1; + break; + default: ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; + break; + } break; case MPI25_VERSION: case MPI26_VERSION: @@ -10524,26 +10532,34 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->transportt = mpt3sas_transport_template; shost->unique_id = ioc->id; - if (max_sectors != 0xFFFF) { - if (max_sectors < 64) { - shost->max_sectors = 64; - pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ - "for max_sectors, range is 64 to 32767. Assigning " - "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 32767) { - shost->max_sectors = 32767; - pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ - "for max_sectors, range is 64 to 32767. Assigning " - "default value of 32767.\n", ioc->name, - max_sectors); - } else { - shost->max_sectors = max_sectors & 0xFFFE; - pr_info(MPT3SAS_FMT + if (ioc->is_mcpu_endpoint) { + /* mCPU MPI support 64K max IO */ + shost->max_sectors = 128; + pr_info(MPT3SAS_FMT "The max_sectors value is set to %d\n", ioc->name, shost->max_sectors); + } else { + if (max_sectors != 0xFFFF) { + if (max_sectors < 64) { + shost->max_sectors = 64; + pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ + "for max_sectors, range is 64 to 32767. " \ + "Assigning value of 64.\n", \ + ioc->name, max_sectors); + } else if (max_sectors > 32767) { + shost->max_sectors = 32767; + pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ + "for max_sectors, range is 64 to 32767." \ + "Assigning default value of 32767.\n", \ + ioc->name, max_sectors); + } else { + shost->max_sectors = max_sectors & 0xFFFE; + pr_info(MPT3SAS_FMT + "The max_sectors value is set to %d\n", + ioc->name, shost->max_sectors); + } } } - /* register EEDP capabilities with SCSI layer */ if (prot_mask > 0) scsi_host_set_prot(shost, prot_mask); @@ -10856,6 +10872,8 @@ static const struct pci_device_id mpt3sas_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP, + PCI_ANY_ID, PCI_ANY_ID }, /* SSS6200 */ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, PCI_ANY_ID, PCI_ANY_ID }, diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index d3940c5d079d..3a143bb5ca72 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -392,7 +392,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, "report_manufacture - send to sas_addr(0x%016llx)\n", ioc->name, (unsigned long long)sas_address)); init_completion(&ioc->transport_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1198,7 +1198,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, ioc->name, (unsigned long long)phy->identify.sas_address, phy->number)); init_completion(&ioc->transport_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1514,7 +1514,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, ioc->name, (unsigned long long)phy->identify.sas_address, phy->number, phy_operation)); init_completion(&ioc->transport_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -2014,7 +2014,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, "%s - sending smp request\n", ioc->name, __func__)); init_completion(&ioc->transport_cmds.done); - ioc->put_smid_default(ioc, smid); + mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index e6b2b681fda3..7d1ab414b78f 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -3,6 +3,9 @@ #include <linux/mm.h> #include <linux/blkdev.h> #include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -14,9 +17,6 @@ #include "wd33c93.h" #include "mvme147.h" -#include <linux/stat.h> - - static irqreturn_t mvme147_intr(int irq, void *data) { struct Scsi_Host *instance = data; @@ -65,40 +65,57 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, m147_pcc->dma_cntrl = 0; } -int mvme147_detect(struct scsi_host_template *tpnt) +static struct scsi_host_template mvme147_host_template = { + .module = THIS_MODULE, + .proc_name = "MVME147", + .name = "MVME147 built-in SCSI", + .queuecommand = wd33c93_queuecommand, + .eh_abort_handler = wd33c93_abort, + .eh_host_reset_handler = wd33c93_host_reset, + .show_info = wd33c93_show_info, + .write_info = wd33c93_write_info, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = ENABLE_CLUSTERING +}; + +static struct Scsi_Host *mvme147_shost; + +static int __init mvme147_init(void) { - static unsigned char called = 0; - struct Scsi_Host *instance; wd33c93_regs regs; struct WD33C93_hostdata *hdata; + int error = -ENOMEM; - if (!MACH_IS_MVME147 || called) + if (!MACH_IS_MVME147) return 0; - called++; - tpnt->proc_name = "MVME147"; - tpnt->show_info = wd33c93_show_info, - tpnt->write_info = wd33c93_write_info, - - instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); - if (!instance) + mvme147_shost = scsi_host_alloc(&mvme147_host_template, + sizeof(struct WD33C93_hostdata)); + if (!mvme147_shost) goto err_out; + mvme147_shost->base = 0xfffe4000; + mvme147_shost->irq = MVME147_IRQ_SCSI_PORT; - instance->base = 0xfffe4000; - instance->irq = MVME147_IRQ_SCSI_PORT; regs.SASR = (volatile unsigned char *)0xfffe4000; regs.SCMD = (volatile unsigned char *)0xfffe4001; - hdata = shost_priv(instance); + + hdata = shost_priv(mvme147_shost); hdata->no_sync = 0xff; hdata->fast = 0; hdata->dma_mode = CTRL_DMA; - wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); - if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, - "MVME147 SCSI PORT", instance)) + wd33c93_init(mvme147_shost, regs, dma_setup, dma_stop, WD33C93_FS_8_10); + + error = request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, + "MVME147 SCSI PORT", mvme147_shost); + if (error) goto err_unregister; - if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, - "MVME147 SCSI DMA", instance)) + error = request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, + "MVME147 SCSI DMA", mvme147_shost); + if (error) goto err_free_irq; #if 0 /* Disabled; causes problems booting */ m147_pcc->scsi_interrupt = 0x10; /* Assert SCSI bus reset */ @@ -112,40 +129,30 @@ int mvme147_detect(struct scsi_host_template *tpnt) m147_pcc->dma_cntrl = 0x00; /* ensure DMA is stopped */ m147_pcc->dma_intr = 0x89; /* Ack and enable ints */ - return 1; + error = scsi_add_host(mvme147_shost, NULL); + if (error) + goto err_free_irq; + scsi_scan_host(mvme147_shost); + return 0; err_free_irq: - free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); + free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost); err_unregister: - scsi_unregister(instance); + scsi_host_put(mvme147_shost); err_out: - return 0; + return error; } -static struct scsi_host_template driver_template = { - .proc_name = "MVME147", - .name = "MVME147 built-in SCSI", - .detect = mvme147_detect, - .release = mvme147_release, - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -int mvme147_release(struct Scsi_Host *instance) +static void __exit mvme147_exit(void) { -#ifdef MODULE + scsi_remove_host(mvme147_shost); + /* XXX Make sure DMA is stopped! */ - free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); - free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr); -#endif - return 1; + free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost); + free_irq(MVME147_IRQ_SCSI_DMA, mvme147_shost); + + scsi_host_put(mvme147_shost); } + +module_init(mvme147_init); +module_exit(mvme147_exit); diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 7de5d8d75480..eb5471bc7263 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -1080,16 +1080,16 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, void __iomem *regs = mvi->regs_ex - 0x10200; int drive = (i/3) & (4-1); /* drive number on host */ - u32 block = mr32(MVS_SGPIO_DCTRL + + int driveshift = drive * 8; /* bit offset of drive */ + u32 block = ioread32be(regs + MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id); - /* * if bit is set then create a mask with the first * bit of the drive set in the mask ... */ - u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ? - 1<<(24-drive*8) : 0; + u32 bit = get_unaligned_be32(write_data) & (1 << i) ? + 1 << driveshift : 0; /* * ... and then shift it to the right position based @@ -1098,26 +1098,27 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, switch (i%3) { case 0: /* activity */ block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT) - << (24-drive*8)); + << driveshift); /* hardwire activity bit to SOF */ block |= LED_BLINKA_SOF << ( MVS_SGPIO_DCTRL_ACT_SHIFT + - (24-drive*8)); + driveshift); break; case 1: /* id */ block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT) - << (24-drive*8)); + << driveshift); block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT; break; case 2: /* fail */ block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT) - << (24-drive*8)); + << driveshift); block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT; break; } - mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, - block); + iowrite32be(block, + regs + MVS_SGPIO_DCTRL + + MVS_SGPIO_HOST_OFFSET * mvi->id); } @@ -1132,7 +1133,7 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv, void __iomem *regs = mvi->regs_ex - 0x10200; mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id, - be32_to_cpu(((u32 *) write_data)[i])); + ((u32 *) write_data)[i]); } return reg_count; } diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index ecc855c550aa..2d435f105b16 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -19,15 +19,6 @@ config PCMCIA_AHA152X To compile this driver as a module, choose M here: the module will be called aha152x_cs. -config PCMCIA_FDOMAIN - tristate "Future Domain PCMCIA support" - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called fdomain_cs. - config PCMCIA_NINJA_SCSI tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support" depends on !64BIT diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile index 44eea2d43143..faa87a4b2d2b 100644 --- a/drivers/scsi/pcmcia/Makefile +++ b/drivers/scsi/pcmcia/Makefile @@ -4,11 +4,9 @@ ccflags-y := -Idrivers/scsi # 16-bit client drivers obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o -obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o aha152x_cs-objs := aha152x_stub.o aha152x_core.o -fdomain_cs-objs := fdomain_stub.o fdomain_core.o qlogic_cs-objs := qlogic_stub.o diff --git a/drivers/scsi/pcmcia/fdomain_core.c b/drivers/scsi/pcmcia/fdomain_core.c deleted file mode 100644 index a48913791868..000000000000 --- a/drivers/scsi/pcmcia/fdomain_core.c +++ /dev/null @@ -1,2 +0,0 @@ -#define PCMCIA 1 -#include "fdomain.c" diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c deleted file mode 100644 index 953a792150ae..000000000000 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ /dev/null @@ -1,209 +0,0 @@ -/*====================================================================== - - A driver for Future Domain-compatible PCMCIA SCSI cards - - fdomain_cs.c 1.47 2001/10/13 00:08:52 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <scsi/scsi.h> -#include <linux/major.h> -#include <linux/blkdev.h> -#include <scsi/scsi_ioctl.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "fdomain.h" - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); -MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); -MODULE_LICENSE("Dual MPL/GPL"); - -/*====================================================================*/ - -typedef struct scsi_info_t { - struct pcmcia_device *p_dev; - struct Scsi_Host *host; -} scsi_info_t; - - -static void fdomain_release(struct pcmcia_device *link); -static void fdomain_detach(struct pcmcia_device *p_dev); -static int fdomain_config(struct pcmcia_device *link); - -static int fdomain_probe(struct pcmcia_device *link) -{ - scsi_info_t *info; - - dev_dbg(&link->dev, "fdomain_attach()\n"); - - /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - link->config_regs = PRESENT_OPTION; - - return fdomain_config(link); -} /* fdomain_attach */ - -/*====================================================================*/ - -static void fdomain_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "fdomain_detach\n"); - - fdomain_release(link); - - kfree(link->priv); -} /* fdomain_detach */ - -/*====================================================================*/ - -static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->io_lines = 10; - p_dev->resource[0]->end = 0x10; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - return pcmcia_request_io(p_dev); -} - - -static int fdomain_config(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - int ret; - char str[22]; - struct Scsi_Host *host; - - dev_dbg(&link->dev, "fdomain_config\n"); - - ret = pcmcia_loop_config(link, fdomain_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* A bad hack... */ - release_region(link->resource[0]->start, resource_size(link->resource[0])); - - /* Set configuration options for the fdomain driver */ - sprintf(str, "%d,%d", (unsigned int) link->resource[0]->start, link->irq); - fdomain_setup(str); - - host = __fdomain_16x0_detect(&fdomain_driver_template); - if (!host) { - printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); - goto failed; - } - - if (scsi_add_host(host, NULL)) - goto failed; - scsi_scan_host(host); - - info->host = host; - - return 0; - -failed: - fdomain_release(link); - return -ENODEV; -} /* fdomain_config */ - -/*====================================================================*/ - -static void fdomain_release(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - - dev_dbg(&link->dev, "fdomain_release\n"); - - scsi_remove_host(info->host); - pcmcia_disable_device(link); - scsi_unregister(info->host); -} - -/*====================================================================*/ - -static int fdomain_resume(struct pcmcia_device *link) -{ - fdomain_16x0_host_reset(NULL); - - return 0; -} - -static const struct pcmcia_device_id fdomain_ids[] = { - PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20), - PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e), - PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, fdomain_ids); - -static struct pcmcia_driver fdomain_cs_driver = { - .owner = THIS_MODULE, - .name = "fdomain_cs", - .probe = fdomain_probe, - .remove = fdomain_detach, - .id_table = fdomain_ids, - .resume = fdomain_resume, -}; - -static int __init init_fdomain_cs(void) -{ - return pcmcia_register_driver(&fdomain_cs_driver); -} - -static void __exit exit_fdomain_cs(void) -{ - pcmcia_unregister_driver(&fdomain_cs_driver); -} - -module_init(init_fdomain_cs); -module_exit(exit_fdomain_cs); diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 201c8de1853d..95530393872d 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -1025,7 +1025,7 @@ static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) { struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + struct pmcraid_ioadl_desc *ioadl; struct pmcraid_instance *pinstance = cmd->drv_inst; u16 data_size = sizeof(struct pmcraid_inquiry_data); @@ -3175,7 +3175,7 @@ static int pmcraid_build_ioadl( struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + struct pmcraid_ioadl_desc *ioadl; u32 length = scsi_bufflen(scsi_cmd); @@ -3225,12 +3225,7 @@ static int pmcraid_build_ioadl( */ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) { - int i; - - for (i = 0; i < sglist->num_sg; i++) - __free_pages(sg_page(&(sglist->scatterlist[i])), - sglist->order); - + sgl_free_order(sglist->scatterlist, sglist->order); kfree(sglist); } @@ -3247,50 +3242,20 @@ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) { struct pmcraid_sglist *sglist; - struct scatterlist *scatterlist; - struct page *page; - int num_elem, i, j; int sg_size; int order; - int bsize_elem; sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); order = (sg_size > 0) ? get_order(sg_size) : 0; - bsize_elem = PAGE_SIZE * (1 << order); - - /* Determine the actual number of sg entries needed */ - if (buflen % bsize_elem) - num_elem = (buflen / bsize_elem) + 1; - else - num_elem = buflen / bsize_elem; /* Allocate a scatter/gather list for the DMA */ - sglist = kzalloc(sizeof(struct pmcraid_sglist) + - (sizeof(struct scatterlist) * (num_elem - 1)), - GFP_KERNEL); - + sglist = kzalloc(sizeof(struct pmcraid_sglist), GFP_KERNEL); if (sglist == NULL) return NULL; - scatterlist = sglist->scatterlist; - sg_init_table(scatterlist, num_elem); sglist->order = order; - sglist->num_sg = num_elem; - sg_size = buflen; - - for (i = 0; i < num_elem; i++) { - page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order); - if (!page) { - for (j = i - 1; j >= 0; j--) - __free_pages(sg_page(&scatterlist[j]), order); - kfree(sglist); - return NULL; - } - - sg_set_page(&scatterlist[i], page, - sg_size < bsize_elem ? sg_size : bsize_elem, 0); - sg_size -= bsize_elem; - } + sgl_alloc_order(buflen, order, false, + GFP_KERNEL | GFP_DMA | __GFP_ZERO, &sglist->num_sg); return sglist; } @@ -5492,7 +5457,7 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) struct pmcraid_instance *pinstance = cmd->drv_inst; struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + struct pmcraid_ioadl_desc *ioadl; u64 timestamp; timestamp = ktime_get_real_seconds() * 1000; @@ -5665,7 +5630,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) static void pmcraid_querycfg(struct pmcraid_cmd *cmd) { struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + struct pmcraid_ioadl_desc *ioadl; struct pmcraid_instance *pinstance = cmd->drv_inst; __be32 cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index 8bfac72a242b..754ef30927e2 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -542,8 +542,7 @@ struct pmcraid_sglist { u32 order; u32 num_sg; u32 num_dma_sg; - u32 buffer_len; - struct scatterlist scatterlist[1]; + struct scatterlist *scatterlist; }; /* page D0 inquiry data of focal point resource */ diff --git a/drivers/scsi/qedf/qedf_dbg.c b/drivers/scsi/qedf/qedf_dbg.c index e023f5d0dc12..bd1cef25a900 100644 --- a/drivers/scsi/qedf/qedf_dbg.c +++ b/drivers/scsi/qedf/qedf_dbg.c @@ -160,7 +160,7 @@ qedf_uevent_emit(struct Scsi_Host *shost, u32 code, char *msg) switch (code) { case QEDF_UEVENT_CODE_GRCDUMP: if (msg) - strncpy(event_string, msg, strlen(msg)); + strscpy(event_string, msg, sizeof(event_string)); else sprintf(event_string, "GRCDUMP=%u", shost->host_no); break; diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h index 50083cae84c3..77c27e888969 100644 --- a/drivers/scsi/qedf/qedf_dbg.h +++ b/drivers/scsi/qedf/qedf_dbg.h @@ -116,6 +116,14 @@ extern int qedf_create_sysfs_attr(struct Scsi_Host *shost, extern void qedf_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter); +struct qedf_debugfs_ops { + char *name; + struct qedf_list_of_funcs *qedf_funcs; +}; + +extern const struct qedf_debugfs_ops qedf_debugfs_ops[]; +extern const struct file_operations qedf_dbg_fops[]; + #ifdef CONFIG_DEBUG_FS /* DebugFS related code */ struct qedf_list_of_funcs { @@ -123,11 +131,6 @@ struct qedf_list_of_funcs { ssize_t (*oper_func)(struct qedf_dbg_ctx *qedf); }; -struct qedf_debugfs_ops { - char *name; - struct qedf_list_of_funcs *qedf_funcs; -}; - #define qedf_dbg_fileops(drv, ops) \ { \ .owner = THIS_MODULE, \ @@ -147,8 +150,8 @@ struct qedf_debugfs_ops { } extern void qedf_dbg_host_init(struct qedf_dbg_ctx *qedf, - struct qedf_debugfs_ops *dops, - struct file_operations *fops); + const struct qedf_debugfs_ops *dops, + const struct file_operations *fops); extern void qedf_dbg_host_exit(struct qedf_dbg_ctx *qedf); extern void qedf_dbg_init(char *drv_name); extern void qedf_dbg_exit(void); diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index 2b1ef3075e93..c539a7ae3a7e 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -23,8 +23,8 @@ static struct dentry *qedf_dbg_root; **/ void qedf_dbg_host_init(struct qedf_dbg_ctx *qedf, - struct qedf_debugfs_ops *dops, - struct file_operations *fops) + const struct qedf_debugfs_ops *dops, + const struct file_operations *fops) { char host_dirname[32]; struct dentry *file_dentry = NULL; @@ -99,7 +99,7 @@ qedf_dbg_exit(void) qedf_dbg_root = NULL; } -struct qedf_debugfs_ops qedf_debugfs_ops[] = { +const struct qedf_debugfs_ops qedf_debugfs_ops[] = { { "fp_int", NULL }, { "io_trace", NULL }, { "debug", NULL }, diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index b15e69586a36..50a50c4249d0 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -917,7 +917,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) struct qedf_ctx *qedf = lport_priv(lport); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); struct fc_rport_libfc_priv *rp = rport->dd_data; - struct qedf_rport *fcport = rport->dd_data; + struct qedf_rport *fcport; struct qedf_ioreq *io_req; int rc = 0; int rval; diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index ccd9a08ea030..284ccb566b19 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -23,6 +23,7 @@ #include <linux/if_vlan.h> #include <linux/cpu.h> #include "qedf.h" +#include "qedf_dbg.h" #include <uapi/linux/pci_regs.h> const struct qed_fcoe_ops *qed_ops; @@ -30,9 +31,6 @@ const struct qed_fcoe_ops *qed_ops; static int qedf_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void qedf_remove(struct pci_dev *pdev); -extern struct qedf_debugfs_ops qedf_debugfs_ops; -extern struct file_operations qedf_dbg_fops; - /* * Driver module parameters. */ @@ -3155,8 +3153,8 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) } #ifdef CONFIG_DEBUG_FS - qedf_dbg_host_init(&(qedf->dbg_ctx), &qedf_debugfs_ops, - &qedf_dbg_fops); + qedf_dbg_host_init(&(qedf->dbg_ctx), qedf_debugfs_ops, + qedf_dbg_fops); #endif /* Start LL2 */ diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h index c55572badfb0..0bc9c31d5a4f 100644 --- a/drivers/scsi/qedi/qedi_dbg.h +++ b/drivers/scsi/qedi/qedi_dbg.h @@ -103,7 +103,6 @@ int qedi_create_sysfs_attr(struct Scsi_Host *shost, void qedi_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter); -#ifdef CONFIG_DEBUG_FS /* DebugFS related code */ struct qedi_list_of_funcs { char *oper_str; @@ -134,11 +133,10 @@ struct qedi_debugfs_ops { } void qedi_dbg_host_init(struct qedi_dbg_ctx *qedi, - struct qedi_debugfs_ops *dops, + const struct qedi_debugfs_ops *dops, const struct file_operations *fops); void qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi); void qedi_dbg_init(char *drv_name); void qedi_dbg_exit(void); -#endif /* CONFIG_DEBUG_FS */ #endif /* _QEDI_DBG_H_ */ diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c index fd8a1eea3163..fd914ca4149a 100644 --- a/drivers/scsi/qedi/qedi_debugfs.c +++ b/drivers/scsi/qedi/qedi_debugfs.c @@ -19,7 +19,7 @@ static struct dentry *qedi_dbg_root; void qedi_dbg_host_init(struct qedi_dbg_ctx *qedi, - struct qedi_debugfs_ops *dops, + const struct qedi_debugfs_ops *dops, const struct file_operations *fops) { char host_dirname[32]; @@ -99,7 +99,7 @@ static struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = { { NULL, NULL } }; -struct qedi_debugfs_ops qedi_debugfs_ops[] = { +const struct qedi_debugfs_ops qedi_debugfs_ops[] = { { "gbl_ctx", NULL }, { "do_not_recover", qedi_dbg_do_not_recover_ops}, { "io_trace", NULL }, diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h index f5b5a31999aa..a2aa06ed1620 100644 --- a/drivers/scsi/qedi/qedi_gbl.h +++ b/drivers/scsi/qedi/qedi_gbl.h @@ -23,8 +23,8 @@ extern uint qedi_io_tracing; extern struct scsi_host_template qedi_host_template; extern struct iscsi_transport qedi_iscsi_transport; extern const struct qed_iscsi_ops *qedi_ops; -extern struct qedi_debugfs_ops qedi_debugfs_ops; -extern const struct file_operations qedi_dbg_fops; +extern const struct qedi_debugfs_ops qedi_debugfs_ops[]; +extern const struct file_operations qedi_dbg_fops[]; extern struct device_attribute *qedi_shost_attrs[]; int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index f57a94b4f0d9..4da3592aec0f 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -2300,8 +2300,8 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) } #ifdef CONFIG_DEBUG_FS - qedi_dbg_host_init(&qedi->dbg_ctx, &qedi_debugfs_ops, - &qedi_dbg_fops); + qedi_dbg_host_init(&qedi->dbg_ctx, qedi_debugfs_ops, + qedi_dbg_fops); #endif QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n", diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index e2d5d3ca0f57..c11a89be292c 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1035,7 +1035,7 @@ qla84xx_updatefw(struct bsg_job *bsg_job) sg_copy_to_buffer(bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, fw_buf, data_len); - mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); + mn = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); if (!mn) { ql_log(ql_log_warn, vha, 0x7036, "DMA alloc failed for fw buffer.\n"); @@ -1046,7 +1046,6 @@ qla84xx_updatefw(struct bsg_job *bsg_job) flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)fw_buf + 2))); - memset(mn, 0, sizeof(struct access_chip_84xx)); mn->entry_type = VERIFY_CHIP_IOCB_TYPE; mn->entry_count = 1; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 3e9dc54b89a3..5fd44c50bbac 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -14,7 +14,7 @@ * | Module Init and Probe | 0x0193 | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | - * | Mailbox commands | 0x1205 | 0x11a2-0x11ff | + * | Mailbox commands | 0x1206 | 0x11a2-0x11ff | * | Device Discovery | 0x2134 | 0x210e-0x2116 | * | | | 0x211a | * | | | 0x211c-0x2128 | @@ -60,7 +60,7 @@ * | | | 0xb13c-0xb140 | * | | | 0xb149 | * | MultiQ | 0xc010 | | - * | Misc | 0xd302 | 0xd031-0xd0ff | + * | Misc | 0xd303 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | * | Target Mode | 0xe081 | | @@ -717,7 +717,7 @@ qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval) /** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. - * @ha: HA context + * @vha: HA context * @hardware_locked: Called with the hardware_lock */ void @@ -887,7 +887,7 @@ qla2300_fw_dump_failed: /** * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. - * @ha: HA context + * @vha: HA context * @hardware_locked: Called with the hardware_lock */ void diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c9689f97c307..eb2ec1fb07cb 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2356,6 +2356,8 @@ typedef struct fc_port { #define NVME_PRLI_SP_DISCOVERY BIT_3 uint8_t nvme_flag; #define NVME_FLAG_REGISTERED 4 +#define NVME_FLAG_DELETING 2 +#define NVME_FLAG_RESETTING 1 struct fc_port *conflict; unsigned char logout_completed; @@ -2981,8 +2983,14 @@ enum scan_flags_t { SF_QUEUED = BIT_1, }; +enum fc4type_t { + FS_FC4TYPE_FCP = BIT_0, + FS_FC4TYPE_NVME = BIT_1, +}; + struct fab_scan_rp { port_id_t id; + enum fc4type_t fc4type; u8 port_name[8]; u8 node_name[8]; }; @@ -3274,6 +3282,7 @@ struct qla_work_evt { } nack; struct { u8 fc4_type; + srb_t *sp; } gpnft; } u; }; @@ -3463,7 +3472,6 @@ struct qla_qpair { struct work_struct q_work; struct list_head qp_list_elem; /* vha->qp_list */ struct list_head hints_list; - struct list_head nvme_done_list; uint16_t cpuid; struct qla_tgt_counters tgt_counters; }; @@ -4281,8 +4289,6 @@ typedef struct scsi_qla_host { struct nvme_fc_local_port *nvme_local_port; struct completion nvme_del_done; struct list_head nvme_rport_list; - atomic_t nvme_active_aen_cnt; - uint16_t nvme_last_rptd_aen; uint16_t fcoe_vlan_id; uint16_t fcoe_fcf_idx; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index e9295398050c..3c4c84ed0f0f 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -658,7 +658,7 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *, struct event_arg *); int qla2x00_mgmt_svr_login(scsi_qla_host_t *); void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea); int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport); -int qla24xx_async_gpnft(scsi_qla_host_t *, u8); +int qla24xx_async_gpnft(scsi_qla_host_t *, u8, srb_t *); void qla24xx_async_gpnft_done(scsi_qla_host_t *, srb_t *); void qla24xx_async_gnnft_done(scsi_qla_host_t *, srb_t *); int qla24xx_async_gnnid(scsi_qla_host_t *, fc_port_t *); @@ -896,6 +896,4 @@ void qlt_update_host_map(struct scsi_qla_host *, port_id_t); void qlt_remove_target_resources(struct qla_hw_data *); void qlt_clr_qp_table(struct scsi_qla_host *vha); -void qla_nvme_cmpl_io(struct srb_iocb *); - #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 403fa096f8c8..2288757b5c9e 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -21,11 +21,10 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *); /** * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query. - * @ha: HA context - * @req_size: request size in bytes - * @rsp_size: response size in bytes + * @vha: HA context + * @arg: CT arguments * - * Returns a pointer to the @ha's ms_iocb. + * Returns a pointer to the @vha's ms_iocb. */ void * qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) @@ -61,9 +60,8 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) /** * qla24xx_prep_ms_iocb() - Prepare common CT IOCB fields for SNS CT query. - * @ha: HA context - * @req_size: request size in bytes - * @rsp_size: response size in bytes + * @vha: HA context + * @arg: CT arguments * * Returns a pointer to the @ha's ms_iocb. */ @@ -101,7 +99,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) /** * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. - * @ct_req: CT request buffer + * @p: CT request buffer * @cmd: GS command * @rsp_size: response size in bytes * @@ -196,7 +194,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, /** * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command. - * @ha: HA context + * @vha: HA context * @fcport: fcport entry to updated * * Returns 0 on success. @@ -283,7 +281,7 @@ qla2x00_gid_pt_rsp_size(scsi_qla_host_t *vha) /** * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * NOTE: Non-Nx_Ports are not requested. @@ -371,7 +369,7 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) /** * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * Returns 0 on success. @@ -441,7 +439,7 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) /** * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * Returns 0 on success. @@ -583,7 +581,7 @@ err2: /** * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -675,7 +673,8 @@ done: /** * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA. - * @ha: HA context + * @vha: HA context + * @type: not used * * Returns 0 on success. */ @@ -769,7 +768,7 @@ done: /** * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -874,7 +873,7 @@ qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn, size_t size) /** * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -970,7 +969,7 @@ done: /** * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. - * @ha: HA context + * @vha: HA context * @cmd: GS command * @scmd_len: Subcommand length * @data_size: response size in bytes @@ -1003,7 +1002,7 @@ qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len, /** * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command. - * @ha: HA context + * @vha: HA context * @fcport: fcport entry to updated * * This command uses the old Exectute SNS Command mailbox routine. @@ -1067,7 +1066,7 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) /** * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * This command uses the old Exectute SNS Command mailbox routine. @@ -1140,7 +1139,7 @@ qla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) /** * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * This command uses the old Exectute SNS Command mailbox routine. @@ -1196,7 +1195,7 @@ qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) /** * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * This command uses the old Exectute SNS Command mailbox routine. @@ -1259,7 +1258,7 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) /** * qla2x00_snd_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. - * @ha: HA context + * @vha: HA context * * This command uses the old Exectute SNS Command mailbox routine. * @@ -1308,8 +1307,7 @@ qla2x00_sns_rft_id(scsi_qla_host_t *vha) /** * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. - * HBA. - * @ha: HA context + * @vha: HA context * * This command uses the old Exectute SNS Command mailbox routine. * @@ -1365,7 +1363,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *vha) /** * qla2x00_mgmt_svr_login() - Login to fabric Management Service. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -1401,7 +1399,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha) /** * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. - * @ha: HA context + * @vha: HA context * @req_size: request size in bytes * @rsp_size: response size in bytes * @@ -1439,7 +1437,7 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, /** * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. - * @ha: HA context + * @vha: HA context * @req_size: request size in bytes * @rsp_size: response size in bytes * @@ -1496,7 +1494,7 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size) /** * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. - * @ct_req: CT request buffer + * @p: CT request buffer * @cmd: GS command * @rsp_size: response size in bytes * @@ -1518,8 +1516,8 @@ qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd, } /** - * qla2x00_fdmi_rhba() - - * @ha: HA context + * qla2x00_fdmi_rhba() - perform RHBA FDMI registration + * @vha: HA context * * Returns 0 on success. */ @@ -1728,8 +1726,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) } /** - * qla2x00_fdmi_rpa() - - * @ha: HA context + * qla2x00_fdmi_rpa() - perform RPA registration + * @vha: HA context * * Returns 0 on success. */ @@ -1940,8 +1938,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) } /** - * qla2x00_fdmiv2_rhba() - - * @ha: HA context + * qla2x00_fdmiv2_rhba() - perform RHBA FDMI v2 registration + * @vha: HA context * * Returns 0 on success. */ @@ -2257,7 +2255,7 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) /** * qla2x00_fdmi_dhba() - - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2305,7 +2303,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha) /** * qla2x00_fdmiv2_rpa() - - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2635,7 +2633,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) /** * qla2x00_fdmi_register() - - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2693,7 +2691,7 @@ out: /** * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * Returns 0 on success. @@ -2778,7 +2776,7 @@ qla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd, /** * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * * Returns 0 on success. @@ -2892,7 +2890,7 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) /** * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. * - * @ha: HA context + * @vha: HA context * @list: switch info entries to populate * */ @@ -3862,7 +3860,6 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) fc_port_t *fcport; u32 i, rc; bool found; - u8 fc4type = sp->gen2; struct fab_scan_rp *rp; unsigned long flags; @@ -3935,7 +3932,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) "%s %d %8phC post new sess\n", __func__, __LINE__, rp->port_name); qla24xx_post_newsess_work(vha, &rp->id, rp->port_name, - rp->node_name, NULL, fc4type); + rp->node_name, NULL, rp->fc4type); } } @@ -3973,24 +3970,114 @@ out: spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); - - if ((fc4type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled) - qla24xx_async_gpnft(vha, FC4_TYPE_NVME); } -static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) +static void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha, + struct srb *sp) { - struct srb *sp = s; - struct scsi_qla_host *vha = sp->vha; - struct qla_work_evt *e; + struct qla_hw_data *ha = vha->hw; + int num_fibre_dev = ha->max_fibre_devices; struct ct_sns_req *ct_req = (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; struct ct_sns_gpnft_rsp *ct_rsp = (struct ct_sns_gpnft_rsp *)sp->u.iocb_cmd.u.ctarg.rsp; struct ct_sns_gpn_ft_data *d; struct fab_scan_rp *rp; + u16 cmd = be16_to_cpu(ct_req->command); + u8 fc4_type = sp->gen2; int i, j, k; + port_id_t id; + u8 found; + u64 wwn; + + j = 0; + for (i = 0; i < num_fibre_dev; i++) { + d = &ct_rsp->entries[i]; + + id.b.rsvd_1 = 0; + id.b.domain = d->port_id[0]; + id.b.area = d->port_id[1]; + id.b.al_pa = d->port_id[2]; + wwn = wwn_to_u64(d->port_name); + + if (id.b24 == 0 || wwn == 0) + continue; + + if (fc4_type == FC4_TYPE_FCP_SCSI) { + if (cmd == GPN_FT_CMD) { + rp = &vha->scan.l[j]; + rp->id = id; + memcpy(rp->port_name, d->port_name, 8); + j++; + rp->fc4type = FS_FC4TYPE_FCP; + } else { + for (k = 0; k < num_fibre_dev; k++) { + rp = &vha->scan.l[k]; + if (id.b24 == rp->id.b24) { + memcpy(rp->node_name, + d->port_name, 8); + break; + } + } + } + } else { + /* Search if the fibre device supports FC4_TYPE_NVME */ + if (cmd == GPN_FT_CMD) { + found = 0; + + for (k = 0; k < num_fibre_dev; k++) { + rp = &vha->scan.l[k]; + if (!memcmp(rp->port_name, + d->port_name, 8)) { + /* + * Supports FC-NVMe & FCP + */ + rp->fc4type |= FS_FC4TYPE_NVME; + found = 1; + break; + } + } + + /* We found new FC-NVMe only port */ + if (!found) { + for (k = 0; k < num_fibre_dev; k++) { + rp = &vha->scan.l[k]; + if (wwn_to_u64(rp->port_name)) { + continue; + } else { + rp->id = id; + memcpy(rp->port_name, + d->port_name, 8); + rp->fc4type = + FS_FC4TYPE_NVME; + break; + } + } + } + } else { + for (k = 0; k < num_fibre_dev; k++) { + rp = &vha->scan.l[k]; + if (id.b24 == rp->id.b24) { + memcpy(rp->node_name, + d->port_name, 8); + break; + } + } + } + } + } +} + +static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) +{ + struct srb *sp = s; + struct scsi_qla_host *vha = sp->vha; + struct qla_work_evt *e; + struct ct_sns_req *ct_req = + (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; u16 cmd = be16_to_cpu(ct_req->command); + u8 fc4_type = sp->gen2; + unsigned long flags; /* gen2 field is holding the fc4type */ ql_dbg(ql_dbg_disc, vha, 0xffff, @@ -4018,40 +4105,51 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) return; } - if (!res) { - port_id_t id; - u64 wwn; - - j = 0; - for (i = 0; i < vha->hw->max_fibre_devices; i++) { - d = &ct_rsp->entries[i]; + if (!res) + qla2x00_find_free_fcp_nvme_slot(vha, sp); - id.b.rsvd_1 = 0; - id.b.domain = d->port_id[0]; - id.b.area = d->port_id[1]; - id.b.al_pa = d->port_id[2]; - wwn = wwn_to_u64(d->port_name); - - if (id.b24 == 0 || wwn == 0) - continue; + if ((fc4_type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled && + cmd == GNN_FT_CMD) { + del_timer(&sp->u.iocb_cmd.timer); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); - if (cmd == GPN_FT_CMD) { - rp = &vha->scan.l[j]; - rp->id = id; - memcpy(rp->port_name, d->port_name, 8); - j++; - } else {/* GNN_FT_CMD */ - for (k = 0; k < vha->hw->max_fibre_devices; - k++) { - rp = &vha->scan.l[k]; - if (id.b24 == rp->id.b24) { - memcpy(rp->node_name, - d->port_name, 8); - break; - } - } + e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT); + if (!e) { + /* + * please ignore kernel warning. Otherwise, + * we have mem leak. + */ + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; } + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async done-%s unable to alloc work element\n", + sp->name); + sp->free(sp); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + return; } + e->u.gpnft.fc4_type = FC4_TYPE_NVME; + sp->rc = res; + e->u.gpnft.sp = sp; + + qla2x00_post_work(vha, e); + return; } if (cmd == GPN_FT_CMD) @@ -4102,9 +4200,12 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, int rval = QLA_FUNCTION_FAILED; struct ct_sns_req *ct_req; struct ct_sns_pkt *ct_sns; + unsigned long flags; if (!vha->flags.online) { + spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); goto done_free_sp; } @@ -4113,10 +4214,18 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, "%s: req %p rsp %p are not setup\n", __func__, sp->u.iocb_cmd.u.ctarg.req, sp->u.iocb_cmd.u.ctarg.rsp); + spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); WARN_ON(1); goto done_free_sp; } + + ql_dbg(ql_dbg_disc, vha, 0xfffff, + "%s: FC4Type %x, CT-PASSTRHU %s command ctarg rsp size %d, ctarg req size %d\n", + __func__, fc4_type, sp->name, sp->u.iocb_cmd.u.ctarg.rsp_size, + sp->u.iocb_cmd.u.ctarg.req_size); + sp->type = SRB_CT_PTHRU_CMD; sp->name = "gnnft"; sp->gen1 = vha->hw->base_qpair->chip_reset; @@ -4179,15 +4288,17 @@ void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp) } /* Get WWPN list for certain fc4_type */ -int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type) +int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) { int rval = QLA_FUNCTION_FAILED; struct ct_sns_req *ct_req; - srb_t *sp; struct ct_sns_pkt *ct_sns; u32 rspsz; unsigned long flags; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s enter\n", __func__); + if (!vha->flags.online) return rval; @@ -4200,9 +4311,58 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type) vha->scan.scan_flags |= SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); - sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); - if (!sp) { - vha->scan.scan_flags &= ~SF_SCANNING; + if (fc4_type == FC4_TYPE_FCP_SCSI) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s: Performing FCP Scan\n", __func__); + + if (sp) + sp->free(sp); /* should not happen */ + + sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); + if (!sp) { + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); + return rval; + } + + sp->u.iocb_cmd.u.ctarg.req = dma_zalloc_coherent( + &vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), + &sp->u.iocb_cmd.u.ctarg.req_dma, GFP_KERNEL); + if (!sp->u.iocb_cmd.u.ctarg.req) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to allocate ct_sns request.\n"); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); + goto done_free_sp; + } + sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE; + + rspsz = sizeof(struct ct_sns_gpnft_rsp) + + ((vha->hw->max_fibre_devices - 1) * + sizeof(struct ct_sns_gpn_ft_data)); + + sp->u.iocb_cmd.u.ctarg.rsp = dma_zalloc_coherent( + &vha->hw->pdev->dev, rspsz, + &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); + if (!sp->u.iocb_cmd.u.ctarg.rsp) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to allocate ct_sns request.\n"); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); + goto done_free_sp; + } + sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz; + + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s scan list size %d\n", __func__, vha->scan.size); + + memset(vha->scan.l, 0, vha->scan.size); + } else if (!sp) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "NVME scan did not provide SP\n"); return rval; } @@ -4212,31 +4372,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type) sp->gen2 = fc4_type; qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - sp->u.iocb_cmd.u.ctarg.req = dma_zalloc_coherent(&vha->hw->pdev->dev, - sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, - GFP_KERNEL); - if (!sp->u.iocb_cmd.u.ctarg.req) { - ql_log(ql_log_warn, vha, 0xffff, - "Failed to allocate ct_sns request.\n"); - vha->scan.scan_flags &= ~SF_SCANNING; - goto done_free_sp; - } - rspsz = sizeof(struct ct_sns_gpnft_rsp) + ((vha->hw->max_fibre_devices - 1) * sizeof(struct ct_sns_gpn_ft_data)); - sp->u.iocb_cmd.u.ctarg.rsp = dma_zalloc_coherent(&vha->hw->pdev->dev, - rspsz, &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); - if (!sp->u.iocb_cmd.u.ctarg.rsp) { - ql_log(ql_log_warn, vha, 0xffff, - "Failed to allocate ct_sns request.\n"); - vha->scan.scan_flags &= ~SF_SCANNING; - goto done_free_sp; - } - - memset(vha->scan.l, 0, vha->scan.size); - ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; /* CT_IU preamble */ ct_req = qla2x00_prep_ct_req(ct_sns, GPN_FT_CMD, rspsz); @@ -4244,8 +4383,6 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type) /* GPN_FT req */ ct_req->req.gpn_ft.port_type = fc4_type; - sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE; - sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz; sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; @@ -4253,7 +4390,9 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type) rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { + spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); goto done_free_sp; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 8d7fab3cd01d..8aeb0ed524a1 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -875,7 +875,6 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) return rval; if (fcport->fw_login_state == DSC_LS_PLOGI_PEND || - fcport->fw_login_state == DSC_LS_PLOGI_COMP || fcport->fw_login_state == DSC_LS_PRLI_PEND) return rval; @@ -1240,6 +1239,11 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) qla2x00_post_async_adisc_work(vha, fcport, data); break; + case DSC_LOGIN_PEND: + if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) + qla24xx_post_prli_work(vha, fcport); + break; + default: break; } @@ -1643,6 +1647,13 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) qla24xx_post_gpdb_work(vha, ea->fcport, 0); break; default: + if ((ea->iop[0] == LSC_SCODE_ELS_REJECT) && + (ea->iop[1] == 0x50000)) { /* reson 5=busy expl:0x0 */ + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + ea->fcport->fw_login_state = DSC_LS_PLOGI_COMP; + break; + } + if (ea->fcport->n2n_flag) { ql_dbg(ql_dbg_disc, vha, 0x2118, "%s %d %8phC post fc4 prli\n", @@ -2049,7 +2060,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) /** * qla2100_pci_config() - Setup ISP21xx PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2080,7 +2091,7 @@ qla2100_pci_config(scsi_qla_host_t *vha) /** * qla2300_pci_config() - Setup ISP23xx PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2162,7 +2173,7 @@ qla2300_pci_config(scsi_qla_host_t *vha) /** * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2206,7 +2217,7 @@ qla24xx_pci_config(scsi_qla_host_t *vha) /** * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2237,7 +2248,7 @@ qla25xx_pci_config(scsi_qla_host_t *vha) /** * qla2x00_isp_firmware() - Choose firmware image. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2273,7 +2284,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha) /** * qla2x00_reset_chip() - Reset ISP chip. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2417,6 +2428,7 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) /** * qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC. + * @vha: HA context * * Returns 0 on success. */ @@ -2433,7 +2445,7 @@ qla81xx_reset_mpi(scsi_qla_host_t *vha) /** * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2648,7 +2660,7 @@ acquired: /** * qla24xx_reset_chip() - Reset ISP24xx chip. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2672,7 +2684,7 @@ qla24xx_reset_chip(scsi_qla_host_t *vha) /** * qla2x00_chip_diag() - Test chip for proper operation. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2691,8 +2703,8 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) /* Assume a failed state */ rval = QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_init, vha, 0x007b, - "Testing device at %lx.\n", (u_long)®->flash_address); + ql_dbg(ql_dbg_init, vha, 0x007b, "Testing device at %p.\n", + ®->flash_address); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -2796,7 +2808,7 @@ chip_diag_failed: /** * qla24xx_chip_diag() - Test ISP24xx for proper operation. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -3264,7 +3276,7 @@ out: /** * qla2x00_setup_chip() - Load and start RISC firmware. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -3419,7 +3431,7 @@ failed: /** * qla2x00_init_response_q_entries() - Initializes response queue entries. - * @ha: HA context + * @rsp: response queue * * Beginning of request ring has initialization control block already built * by nvram config routine. @@ -3444,7 +3456,7 @@ qla2x00_init_response_q_entries(struct rsp_que *rsp) /** * qla2x00_update_fw_options() - Read and process firmware options. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -3707,7 +3719,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha) /** * qla2x00_init_rings() - Initializes firmware. - * @ha: HA context + * @vha: HA context * * Beginning of request ring has initialization control block already built * by nvram config routine. @@ -3815,7 +3827,7 @@ next_check: /** * qla2x00_fw_ready() - Waits for firmware ready. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -4483,7 +4495,7 @@ qla2x00_rport_del(void *data) /** * qla2x00_alloc_fcport() - Allocate a generic fcport. - * @ha: HA context + * @vha: HA context * @flags: allocation flags * * Returns a pointer to the allocated fcport, or NULL, if none available. @@ -5027,9 +5039,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]); } else { ql_dbg(ql_dbg_disc, vha, 0x2005, - "iIDMA adjusted to %s GB/s on %8phN.\n", + "iIDMA adjusted to %s GB/s (%X) on %8phN.\n", qla2x00_get_link_speed_str(ha, fcport->fp_speed), - fcport->port_name); + fcport->fp_speed, fcport->port_name); } } @@ -5109,13 +5121,14 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->deleted = 0; fcport->logout_on_delete = 1; + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + qla2x00_iidma_fcport(vha, fcport); + if (fcport->fc4f_nvme) { qla_nvme_register_remote(vha, fcport); return; } - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - qla2x00_iidma_fcport(vha, fcport); qla24xx_update_fcport_fcp_prio(vha, fcport); reg_port: @@ -5254,8 +5267,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) qlt_do_generation_tick(vha, &discovery_gen); if (USE_ASYNC_SCAN(ha)) { - rval = QLA_SUCCESS; - rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI); + rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI, + NULL); if (rval) set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } else { @@ -5518,6 +5531,14 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) break; } + if (fcport->fc4f_nvme) { + if (fcport->disc_state == DSC_DELETE_PEND) { + fcport->disc_state = DSC_GNL; + vha->fcport_count--; + fcport->login_succ = 0; + } + } + if (found) { spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); continue; @@ -8398,7 +8419,6 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->vp_idx = vp_idx; qpair->fw_started = ha->flags.fw_started; INIT_LIST_HEAD(&qpair->hints_list); - INIT_LIST_HEAD(&qpair->nvme_done_list); qpair->chip_reset = ha->base_qpair->chip_reset; qpair->enable_class_2 = ha->base_qpair->enable_class_2; qpair->enable_explicit_conf = diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 4d32426393c7..b7a05aebf065 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -10,6 +10,7 @@ * qla24xx_calc_iocbs() - Determine number of Command Type 3 and * Continuation Type 1 IOCBs to allocate. * + * @vha: HA context * @dsds: number of data segment decriptors needed * * Returns the number of IOCB entries needed to store @dsds. diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8d00d559bd26..f74ff7b550b6 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -14,7 +14,7 @@ /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. - * @cmd: SCSI command + * @sp: SCSI command * * Returns the proper CF_* direction based on CDB. */ @@ -86,7 +86,7 @@ qla2x00_calc_iocbs_64(uint16_t dsds) /** * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB. - * @ha: HA context + * @vha: HA context * * Returns a pointer to the Continuation Type 0 IOCB packet. */ @@ -114,7 +114,8 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) /** * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB. - * @ha: HA context + * @vha: HA context + * @req: request queue * * Returns a pointer to the continuation type 1 IOCB packet. */ @@ -445,6 +446,8 @@ queuing_error: /** * qla2x00_start_iocbs() - Execute the IOCB command + * @vha: HA context + * @req: request queue */ void qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) @@ -486,7 +489,9 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) /** * qla2x00_marker() - Send a marker IOCB to the firmware. - * @ha: HA context + * @vha: HA context + * @req: request queue + * @rsp: response queue * @loop_id: loop ID * @lun: LUN * @type: marker modifier @@ -1190,6 +1195,8 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, * @sp: SRB command to process * @cmd_pkt: Command type 3 IOCB * @tot_dsds: Total number of segments to transfer + * @tot_prot_dsds: + * @fw_prot_opts: */ inline int qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, @@ -1203,7 +1210,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, uint32_t dif_bytes; uint8_t bundling = 1; uint16_t blk_size; - uint8_t *clr_ptr; struct crc_context *crc_ctx_pkt = NULL; struct qla_hw_data *ha; uint8_t additional_fcpcdb_len; @@ -1245,15 +1251,11 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, /* Allocate CRC context from global pool */ crc_ctx_pkt = sp->u.scmd.ctx = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); + dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); if (!crc_ctx_pkt) goto crc_queuing_error; - /* Zero out CTX area. */ - clr_ptr = (uint8_t *)crc_ctx_pkt; - memset(clr_ptr, 0, sizeof(*crc_ctx_pkt)); - crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; sp->flags |= SRB_CRC_CTX_DMA_VALID; @@ -3067,7 +3069,7 @@ sufficient_dsds: } memset(ctx, 0, sizeof(struct ct6_dsd)); - ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool, + ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, GFP_ATOMIC, &ctx->fcp_cmnd_dma); if (!ctx->fcp_cmnd) { ql_log(ql_log_fatal, vha, 0x3011, @@ -3120,7 +3122,6 @@ sufficient_dsds: host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); /* build FCP_CMND IU */ - memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun); ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 89f93ebd819d..7cacdc3408fa 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -259,7 +259,7 @@ qla2300_intr_handler(int irq, void *dev_id) /** * qla2x00_mbx_completion() - Process mailbox command completions. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context * @mb0: Mailbox0 register */ static void @@ -613,7 +613,8 @@ qla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id, /** * qla2x00_async_event() - Process aynchronous events. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue * @mb: Mailbox registers (0 - 3) */ void @@ -767,7 +768,6 @@ skip_rio: case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ ha->flags.lip_ae = 1; - ha->flags.n2n_ae = 0; ql_dbg(ql_dbg_async, vha, 0x5009, "LIP occurred (%x).\n", mb[1]); @@ -811,7 +811,6 @@ skip_rio: case MBA_LOOP_DOWN: /* Loop Down Event */ SAVE_TOPO(ha); - ha->flags.n2n_ae = 0; ha->flags.lip_ae = 0; ha->current_topology = 0; @@ -885,7 +884,6 @@ skip_rio: /* case MBA_DCBX_COMPLETE: */ case MBA_POINT_TO_POINT: /* Point-to-Point */ ha->flags.lip_ae = 0; - ha->flags.n2n_ae = 1; if (IS_QLA2100(ha)) break; @@ -1256,7 +1254,8 @@ global_port_update: /** * qla2x00_process_completed_request() - Process a Fast Post response. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @req: request queue * @index: SRB index */ void @@ -1839,31 +1838,23 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) sp->done(sp, 0); } -static void -qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) +static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + void *tsk, srb_t *sp) { - const char func[] = "NVME-IOCB"; fc_port_t *fcport; - srb_t *sp; struct srb_iocb *iocb; struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; uint16_t state_flags; struct nvmefc_fcp_req *fd; uint16_t ret = 0; - struct srb_iocb *nvme; - - sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); - if (!sp) - return; iocb = &sp->u.iocb_cmd; fcport = sp->fcport; iocb->u.nvme.comp_status = le16_to_cpu(sts->comp_status); state_flags = le16_to_cpu(sts->state_flags); fd = iocb->u.nvme.desc; - nvme = &sp->u.iocb_cmd; - if (unlikely(nvme->u.nvme.aen_op)) + if (unlikely(iocb->u.nvme.aen_op)) atomic_dec(&sp->vha->hw->nvme_active_aen_cnt); /* @@ -1897,42 +1888,30 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) fd->transferred_length = fd->payload_length - le32_to_cpu(sts->residual_len); - /* - * If transport error then Failure (HBA rejects request) - * otherwise transport will handle. - */ - if (sts->entry_status) { - ql_log(ql_log_warn, fcport->vha, 0x5038, - "NVME-%s error - hdl=%x entry-status(%x).\n", - sp->name, sp->handle, sts->entry_status); + switch (le16_to_cpu(sts->comp_status)) { + case CS_COMPLETE: + ret = QLA_SUCCESS; + break; + case CS_ABORTED: + case CS_RESET: + case CS_PORT_UNAVAILABLE: + case CS_PORT_LOGGED_OUT: + case CS_PORT_BUSY: + ql_log(ql_log_warn, fcport->vha, 0x5060, + "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n", + sp->name, sp->handle, sts->comp_status, + le32_to_cpu(sts->residual_len), sts->ox_id); + fd->transferred_length = 0; + iocb->u.nvme.rsp_pyld_len = 0; + ret = QLA_ABORTED; + break; + default: + ql_log(ql_log_warn, fcport->vha, 0x5060, + "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n", + sp->name, sp->handle, sts->comp_status, + le32_to_cpu(sts->residual_len), sts->ox_id); ret = QLA_FUNCTION_FAILED; - } else { - switch (le16_to_cpu(sts->comp_status)) { - case CS_COMPLETE: - ret = 0; - break; - - case CS_ABORTED: - case CS_RESET: - case CS_PORT_UNAVAILABLE: - case CS_PORT_LOGGED_OUT: - case CS_PORT_BUSY: - ql_log(ql_log_warn, fcport->vha, 0x5060, - "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n", - sp->name, sp->handle, sts->comp_status, - le32_to_cpu(sts->residual_len), sts->ox_id); - fd->transferred_length = fd->payload_length; - ret = QLA_ABORTED; - break; - - default: - ql_log(ql_log_warn, fcport->vha, 0x5060, - "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n", - sp->name, sp->handle, sts->comp_status, - le32_to_cpu(sts->residual_len), sts->ox_id); - ret = QLA_FUNCTION_FAILED; - break; - } + break; } sp->done(sp, ret); } @@ -1970,7 +1949,7 @@ static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req, /** * qla2x00_process_response_queue() - Process response queue entries. - * @ha: SCSI driver HA context + * @rsp: response queue */ void qla2x00_process_response_queue(struct rsp_que *rsp) @@ -2374,7 +2353,8 @@ done: /** * qla2x00_status_entry() - Process a Status IOCB entry. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue * @pkt: Entry pointer */ static void @@ -2459,7 +2439,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) /* NVME completion. */ if (sp->type == SRB_NVME_CMD) { - qla24xx_nvme_iocb_entry(vha, req, pkt); + req->outstanding_cmds[handle] = NULL; + qla24xx_nvme_iocb_entry(vha, req, pkt, sp); return; } @@ -2751,7 +2732,7 @@ out: /** * qla2x00_status_cont_entry() - Process a Status Continuations entry. - * @ha: SCSI driver HA context + * @rsp: response queue * @pkt: Entry pointer * * Extended sense data. @@ -2809,7 +2790,8 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) /** * qla2x00_error_entry() - Process an error entry. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue * @pkt: Entry pointer * return : 1=allow further error analysis. 0=no additional error analysis. */ @@ -2868,7 +2850,7 @@ fatal: /** * qla24xx_mbx_completion() - Process mailbox command completions. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context * @mb0: Mailbox0 register */ static void @@ -2937,7 +2919,8 @@ void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha, /** * qla24xx_process_response_queue() - Process response queue entries. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue */ void qla24xx_process_response_queue(struct scsi_qla_host *vha, struct rsp_que *rsp) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 7397aeddd96c..5db0262d5c94 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -503,11 +503,19 @@ mbx_done: } pr_warn(" cmd=%x ****\n", command); } - ql_dbg(ql_dbg_mbx, vha, 0x1198, - "host_status=%#x intr_ctrl=%#x intr_status=%#x\n", - RD_REG_DWORD(®->isp24.host_status), - RD_REG_DWORD(®->isp24.ictrl), - RD_REG_DWORD(®->isp24.istatus)); + if (IS_FWI2_CAPABLE(ha) && !(IS_P3P_TYPE(ha))) { + ql_dbg(ql_dbg_mbx, vha, 0x1198, + "host_status=%#x intr_ctrl=%#x intr_status=%#x\n", + RD_REG_DWORD(®->isp24.host_status), + RD_REG_DWORD(®->isp24.ictrl), + RD_REG_DWORD(®->isp24.istatus)); + } else { + ql_dbg(ql_dbg_mbx, vha, 0x1206, + "ctrl_status=%#x ictrl=%#x istatus=%#x\n", + RD_REG_WORD(®->isp.ctrl_status), + RD_REG_WORD(®->isp.ictrl), + RD_REG_WORD(®->isp.istatus)); + } } else { ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__); } @@ -1025,9 +1033,12 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) * FW supports nvme and driver load parameter requested nvme. * BIT 26 of fw_attributes indicates NVMe support. */ - if ((ha->fw_attributes_h & 0x400) && ql2xnvmeenable) + if ((ha->fw_attributes_h & 0x400) && ql2xnvmeenable) { vha->flags.nvme_enabled = 1; - + ql_log(ql_log_info, vha, 0xd302, + "%s: FC-NVMe is Enabled (0x%x)\n", + __func__, ha->fw_attributes_h); + } } if (IS_QLA27XX(ha)) { @@ -3385,7 +3396,10 @@ qla8044_read_serdes_word(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data) /** * qla2x00_set_serdes_params() - - * @ha: HA context + * @vha: HA context + * @sw_em_1g: + * @sw_em_2g: + * @sw_em_4g: * * Returns */ @@ -3744,6 +3758,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, id.b.area = rptid_entry->port_id[1]; id.b.al_pa = rptid_entry->port_id[0]; id.b.rsvd_1 = 0; + ha->flags.n2n_ae = 0; if (rptid_entry->format == 0) { /* loop */ @@ -3796,6 +3811,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); + ha->flags.n2n_ae = 1; return; } @@ -3872,6 +3888,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, vha->d_id.b.area = rptid_entry->port_id[1]; vha->d_id.b.al_pa = rptid_entry->port_id[0]; + ha->flags.n2n_ae = 1; spin_lock_irqsave(&ha->vport_slock, flags); qlt_update_vp_map(vha, SET_AL_PA); spin_unlock_irqrestore(&ha->vport_slock, flags); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index e965b16f21e3..da85cd89639f 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -778,18 +778,12 @@ static void qla_do_work(struct work_struct *work) struct qla_qpair *qpair = container_of(work, struct qla_qpair, q_work); struct scsi_qla_host *vha; struct qla_hw_data *ha = qpair->hw; - struct srb_iocb *nvme, *nxt_nvme; spin_lock_irqsave(&qpair->qp_lock, flags); vha = pci_get_drvdata(ha->pdev); qla24xx_process_response_queue(vha, qpair->rsp); spin_unlock_irqrestore(&qpair->qp_lock, flags); - list_for_each_entry_safe(nvme, nxt_nvme, &qpair->nvme_done_list, - u.nvme.entry) { - list_del_init(&nvme->u.nvme.entry); - qla_nvme_cmpl_io(nvme); - } } /* create response queue */ diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index d5da3981cefe..7113acf42ff3 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -490,7 +490,7 @@ qlafx00_mbx_reg_test(scsi_qla_host_t *vha) /** * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -519,9 +519,9 @@ qlafx00_pci_config(scsi_qla_host_t *vha) /** * qlafx00_warm_reset() - Perform warm reset of iSA(CPUs being reset on SOC). - * @ha: HA context + * @vha: HA context * - */ + */ static inline void qlafx00_soc_cpu_reset(scsi_qla_host_t *vha) { @@ -625,7 +625,7 @@ qlafx00_soc_cpu_reset(scsi_qla_host_t *vha) /** * qlafx00_soft_reset() - Soft Reset ISPFx00. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -644,7 +644,7 @@ qlafx00_soft_reset(scsi_qla_host_t *vha) /** * qlafx00_chip_diag() - Test ISPFx00 for proper operation. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -1408,7 +1408,7 @@ qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp) /** * qlafx00_init_response_q_entries() - Initializes response queue entries. - * @ha: HA context + * @rsp: response queue * * Beginning of request ring has initialization control block already built * by nvram config routine. @@ -2269,7 +2269,8 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req, /** * qlafx00_status_entry() - Process a Status IOCB entry. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue * @pkt: Entry pointer */ static void @@ -2542,7 +2543,7 @@ check_scsi_status: /** * qlafx00_status_cont_entry() - Process a Status Continuations entry. - * @ha: SCSI driver HA context + * @rsp: response queue * @pkt: Entry pointer * * Extended sense data. @@ -2620,7 +2621,9 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) /** * qlafx00_multistatus_entry() - Process Multi response queue entries. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue + * @pkt: */ static void qlafx00_multistatus_entry(struct scsi_qla_host *vha, @@ -2674,8 +2677,11 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha, /** * qlafx00_error_entry() - Process an error entry. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue * @pkt: Entry pointer + * @estatus: + * @etype: */ static void qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, @@ -2705,7 +2711,8 @@ qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, /** * qlafx00_process_response_queue() - Process response queue entries. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context + * @rsp: response queue */ static void qlafx00_process_response_queue(struct scsi_qla_host *vha, @@ -2781,7 +2788,7 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha, /** * qlafx00_async_event() - Process aynchronous events. - * @ha: SCSI driver HA context + * @vha: SCSI driver HA context */ static void qlafx00_async_event(scsi_qla_host_t *vha) @@ -2857,10 +2864,9 @@ qlafx00_async_event(scsi_qla_host_t *vha) } /** - * * qlafx00x_mbx_completion() - Process mailbox command completions. - * @ha: SCSI driver HA context - * @mb16: Mailbox16 register + * @vha: SCSI driver HA context + * @mb0: */ static void qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 6b33a1f24f56..c5a963c2c86e 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -16,15 +16,13 @@ static void qla_nvme_unregister_remote_port(struct work_struct *); int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) { - struct nvme_rport *rport; + struct qla_nvme_rport *rport; + struct nvme_fc_port_info req; int ret; if (!IS_ENABLED(CONFIG_NVME_FC)) return 0; - if (fcport->nvme_flag & NVME_FLAG_REGISTERED) - return 0; - if (!vha->flags.nvme_enabled) { ql_log(ql_log_info, vha, 0x2100, "%s: Not registering target since Host NVME is not enabled\n", @@ -33,38 +31,36 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) } if (!(fcport->nvme_prli_service_param & - (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY))) + (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)) || + (fcport->nvme_flag & NVME_FLAG_REGISTERED)) return 0; INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port); - rport = kzalloc(sizeof(*rport), GFP_KERNEL); - if (!rport) { - ql_log(ql_log_warn, vha, 0x2101, - "%s: unable to alloc memory\n", __func__); - return -ENOMEM; - } + fcport->nvme_flag &= ~NVME_FLAG_RESETTING; - rport->req.port_name = wwn_to_u64(fcport->port_name); - rport->req.node_name = wwn_to_u64(fcport->node_name); - rport->req.port_role = 0; + memset(&req, 0, sizeof(struct nvme_fc_port_info)); + req.port_name = wwn_to_u64(fcport->port_name); + req.node_name = wwn_to_u64(fcport->node_name); + req.port_role = 0; + req.dev_loss_tmo = NVME_FC_DEV_LOSS_TMO; if (fcport->nvme_prli_service_param & NVME_PRLI_SP_INITIATOR) - rport->req.port_role = FC_PORT_ROLE_NVME_INITIATOR; + req.port_role = FC_PORT_ROLE_NVME_INITIATOR; if (fcport->nvme_prli_service_param & NVME_PRLI_SP_TARGET) - rport->req.port_role |= FC_PORT_ROLE_NVME_TARGET; + req.port_role |= FC_PORT_ROLE_NVME_TARGET; if (fcport->nvme_prli_service_param & NVME_PRLI_SP_DISCOVERY) - rport->req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY; + req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY; - rport->req.port_id = fcport->d_id.b24; + req.port_id = fcport->d_id.b24; ql_log(ql_log_info, vha, 0x2102, "%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n", - __func__, rport->req.node_name, rport->req.port_name, - rport->req.port_id); + __func__, req.node_name, req.port_name, + req.port_id); - ret = nvme_fc_register_remoteport(vha->nvme_local_port, &rport->req, + ret = nvme_fc_register_remoteport(vha->nvme_local_port, &req, &fcport->nvme_remote_port); if (ret) { ql_log(ql_log_warn, vha, 0x212e, @@ -73,10 +69,11 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) return ret; } - fcport->nvme_remote_port->private = fcport; - fcport->nvme_flag |= NVME_FLAG_REGISTERED; + rport = fcport->nvme_remote_port->private; rport->fcport = fcport; list_add_tail(&rport->list, &vha->nvme_rport_list); + + fcport->nvme_flag |= NVME_FLAG_REGISTERED; return 0; } @@ -113,8 +110,6 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, return 0; } - ql_log(ql_log_warn, vha, 0xffff, - "allocating q for idx=%x w/o cpu mask\n", qidx); qpair = qla2xxx_create_qpair(vha, 5, vha->vp_idx, true); if (qpair == NULL) { ql_log(ql_log_warn, vha, 0x2122, @@ -154,16 +149,6 @@ static void qla_nvme_sp_ls_done(void *ptr, int res) qla2x00_rel_sp(sp); } -void qla_nvme_cmpl_io(struct srb_iocb *nvme) -{ - srb_t *sp; - struct nvmefc_fcp_req *fd = nvme->u.nvme.desc; - - sp = container_of(nvme, srb_t, u.iocb_cmd); - fd->done(fd); - qla2xxx_rel_qpair_sp(sp->qpair, sp); -} - static void qla_nvme_sp_done(void *ptr, int res) { srb_t *sp = ptr; @@ -176,36 +161,42 @@ static void qla_nvme_sp_done(void *ptr, int res) if (!atomic_dec_and_test(&sp->ref_count)) return; - if (!(sp->fcport->nvme_flag & NVME_FLAG_REGISTERED)) - goto rel; - - if (unlikely(res == QLA_FUNCTION_FAILED)) - fd->status = NVME_SC_INTERNAL; - else + if (res == QLA_SUCCESS) fd->status = 0; + else + fd->status = NVME_SC_INTERNAL; fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len; - list_add_tail(&nvme->u.nvme.entry, &sp->qpair->nvme_done_list); - return; -rel: + fd->done(fd); qla2xxx_rel_qpair_sp(sp->qpair, sp); + + return; } -static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, - struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) +static void qla_nvme_abort_work(struct work_struct *work) { - struct nvme_private *priv = fd->private; - fc_port_t *fcport = rport->private; + struct nvme_private *priv = + container_of(work, struct nvme_private, abort_work); srb_t *sp = priv->sp; - int rval; + fc_port_t *fcport = sp->fcport; struct qla_hw_data *ha = fcport->vha->hw; + int rval; rval = ha->isp_ops->abort_command(sp); ql_dbg(ql_dbg_io, fcport->vha, 0x212b, - "%s: %s LS command for sp=%p on fcport=%p rval=%x\n", __func__, - (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted", - sp, fcport, rval); + "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n", + __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted", + sp, sp->handle, fcport, rval); +} + +static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, + struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) +{ + struct nvme_private *priv = fd->private; + + INIT_WORK(&priv->abort_work, qla_nvme_abort_work); + schedule_work(&priv->abort_work); } static void qla_nvme_ls_complete(struct work_struct *work) @@ -220,7 +211,8 @@ static void qla_nvme_ls_complete(struct work_struct *work) static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) { - fc_port_t *fcport = rport->private; + struct qla_nvme_rport *qla_rport = rport->private; + fc_port_t *fcport = qla_rport->fcport; struct srb_iocb *nvme; struct nvme_private *priv = fd->private; struct scsi_qla_host *vha; @@ -228,9 +220,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, struct qla_hw_data *ha; srb_t *sp; - if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED)) - return rval; - vha = fcport->vha; ha = vha->hw; /* Alloc SRB structure */ @@ -275,32 +264,23 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, struct nvmefc_fcp_req *fd) { struct nvme_private *priv = fd->private; - srb_t *sp = priv->sp; - int rval; - fc_port_t *fcport = rport->private; - struct qla_hw_data *ha = fcport->vha->hw; - - rval = ha->isp_ops->abort_command(sp); - ql_dbg(ql_dbg_io, fcport->vha, 0x2127, - "%s: %s command for sp=%p on fcport=%p rval=%x\n", __func__, - (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted", - sp, fcport, rval); + INIT_WORK(&priv->abort_work, qla_nvme_abort_work); + schedule_work(&priv->abort_work); } static void qla_nvme_poll(struct nvme_fc_local_port *lport, void *hw_queue_handle) { - struct scsi_qla_host *vha = lport->private; - unsigned long flags; struct qla_qpair *qpair = hw_queue_handle; + unsigned long flags; + struct scsi_qla_host *vha = lport->private; - /* Acquire ring specific lock */ spin_lock_irqsave(&qpair->qp_lock, flags); qla24xx_process_response_queue(vha, qpair->rsp); spin_unlock_irqrestore(&qpair->qp_lock, flags); } -static int qla2x00_start_nvme_mq(srb_t *sp) +static inline int qla2x00_start_nvme_mq(srb_t *sp) { unsigned long flags; uint32_t *clr_ptr; @@ -313,7 +293,6 @@ static int qla2x00_start_nvme_mq(srb_t *sp) uint16_t avail_dsds; uint32_t *cur_dsd; struct req_que *req = NULL; - struct rsp_que *rsp = NULL; struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; struct qla_qpair *qpair = sp->qpair; @@ -322,15 +301,13 @@ static int qla2x00_start_nvme_mq(srb_t *sp) struct nvmefc_fcp_req *fd = nvme->u.nvme.desc; uint32_t rval = QLA_SUCCESS; + /* Setup qpair pointers */ + req = qpair->req; tot_dsds = fd->sg_cnt; /* Acquire qpair specific lock */ spin_lock_irqsave(&qpair->qp_lock, flags); - /* Setup qpair pointers */ - req = qpair->req; - rsp = qpair->rsp; - /* Check for room in outstanding command list. */ handle = req->current_outstanding_cmd; for (index = 1; index < req->num_outstanding_cmds; index++) { @@ -342,7 +319,7 @@ static int qla2x00_start_nvme_mq(srb_t *sp) } if (index == req->num_outstanding_cmds) { - rval = -1; + rval = -EBUSY; goto queuing_error; } req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); @@ -356,7 +333,7 @@ static int qla2x00_start_nvme_mq(srb_t *sp) req->cnt = req->length - (req->ring_index - cnt); if (req->cnt < (req_cnt + 2)){ - rval = -1; + rval = -EBUSY; goto queuing_error; } } @@ -365,7 +342,7 @@ static int qla2x00_start_nvme_mq(srb_t *sp) struct nvme_fc_cmd_iu *cmd = fd->cmdaddr; if (cmd->sqe.common.opcode == nvme_admin_async_event) { nvme->u.nvme.aen_op = 1; - atomic_inc(&vha->hw->nvme_active_aen_cnt); + atomic_inc(&ha->nvme_active_aen_cnt); } } @@ -478,11 +455,6 @@ static int qla2x00_start_nvme_mq(srb_t *sp) /* Set chip new ring index. */ WRT_REG_DWORD(req->req_q_in, req->ring_index); - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); - queuing_error: spin_unlock_irqrestore(&qpair->qp_lock, flags); return rval; @@ -496,31 +468,44 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, fc_port_t *fcport; struct srb_iocb *nvme; struct scsi_qla_host *vha; - int rval = QLA_FUNCTION_FAILED; + int rval = -ENODEV; srb_t *sp; struct qla_qpair *qpair = hw_queue_handle; struct nvme_private *priv; + struct qla_nvme_rport *qla_rport = rport->private; - if (!fd) { - ql_log(ql_log_warn, NULL, 0x2134, "NO NVMe FCP request\n"); + if (!fd || !qpair) { + ql_log(ql_log_warn, NULL, 0x2134, + "NO NVMe request or Queue Handle\n"); return rval; } priv = fd->private; - fcport = rport->private; + fcport = qla_rport->fcport; if (!fcport) { ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n"); return rval; } vha = fcport->vha; - if ((!qpair) || (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))) + + if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) + return rval; + + /* + * If we know the dev is going away while the transport is still sending + * IO's return busy back to stall the IO Q. This happens when the + * link goes away and fw hasn't notified us yet, but IO's are being + * returned. If the dev comes back quickly we won't exhaust the IO + * retry count at the core. + */ + if (fcport->nvme_flag & NVME_FLAG_RESETTING) return -EBUSY; /* Alloc SRB structure */ sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); if (!sp) - return -EIO; + return -EBUSY; atomic_set(&sp->ref_count, 1); init_waitqueue_head(&sp->nvme_ls_waitq); @@ -538,7 +523,6 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, "qla2x00_start_nvme_mq failed = %d\n", rval); atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); - return -EIO; } return rval; @@ -557,22 +541,27 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport) static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) { fc_port_t *fcport; - struct nvme_rport *r_port, *trport; + struct qla_nvme_rport *qla_rport = rport->private, *trport; - fcport = rport->private; + fcport = qla_rport->fcport; fcport->nvme_remote_port = NULL; fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; - list_for_each_entry_safe(r_port, trport, + list_for_each_entry_safe(qla_rport, trport, &fcport->vha->nvme_rport_list, list) { - if (r_port->fcport == fcport) { - list_del(&r_port->list); + if (qla_rport->fcport == fcport) { + list_del(&qla_rport->list); break; } } - kfree(r_port); complete(&fcport->nvme_del_done); + if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) { + INIT_WORK(&fcport->free_work, qlt_free_session_done); + schedule_work(&fcport->free_work); + } + + fcport->nvme_flag &= ~(NVME_FLAG_REGISTERED | NVME_FLAG_DELETING); ql_log(ql_log_info, fcport->vha, 0x2110, "remoteport_delete of %p completed.\n", fcport); } @@ -592,7 +581,7 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .max_dif_sgl_segments = 64, .dma_boundary = 0xFFFFFFFF, .local_priv_sz = 8, - .remote_priv_sz = 0, + .remote_priv_sz = sizeof(struct qla_nvme_rport), .lsrqst_priv_sz = sizeof(struct nvme_private), .fcprqst_priv_sz = sizeof(struct nvme_private), }; @@ -611,37 +600,25 @@ static int qla_nvme_wait_on_command(srb_t *sp) return ret; } -static int qla_nvme_wait_on_rport_del(fc_port_t *fcport) -{ - int ret = QLA_SUCCESS; - int timeout; - - timeout = wait_for_completion_timeout(&fcport->nvme_del_done, - msecs_to_jiffies(2000)); - if (!timeout) { - ret = QLA_FUNCTION_FAILED; - ql_log(ql_log_info, fcport->vha, 0x2111, - "timed out waiting for fcport=%p to delete\n", fcport); - } - - return ret; -} - -void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp) +void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp, int res) { int rval; - rval = ha->isp_ops->abort_command(sp); - if (!rval && !qla_nvme_wait_on_command(sp)) - ql_log(ql_log_warn, NULL, 0x2112, - "nvme_wait_on_comand timed out waiting on sp=%p\n", sp); + if (!test_bit(ABORT_ISP_ACTIVE, &sp->vha->dpc_flags)) { + rval = ha->isp_ops->abort_command(sp); + if (!rval && !qla_nvme_wait_on_command(sp)) + ql_log(ql_log_warn, NULL, 0x2112, + "timed out waiting on sp=%p\n", sp); + } else { + sp->done(sp, res); + } } static void qla_nvme_unregister_remote_port(struct work_struct *work) { struct fc_port *fcport = container_of(work, struct fc_port, nvme_del_work); - struct nvme_rport *rport, *trport; + struct qla_nvme_rport *qla_rport, *trport; if (!IS_ENABLED(CONFIG_NVME_FC)) return; @@ -649,51 +626,53 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) ql_log(ql_log_warn, NULL, 0x2112, "%s: unregister remoteport on %p\n",__func__, fcport); - list_for_each_entry_safe(rport, trport, + list_for_each_entry_safe(qla_rport, trport, &fcport->vha->nvme_rport_list, list) { - if (rport->fcport == fcport) { + if (qla_rport->fcport == fcport) { ql_log(ql_log_info, fcport->vha, 0x2113, "%s: fcport=%p\n", __func__, fcport); init_completion(&fcport->nvme_del_done); nvme_fc_unregister_remoteport( fcport->nvme_remote_port); - qla_nvme_wait_on_rport_del(fcport); + wait_for_completion(&fcport->nvme_del_done); + break; } } } void qla_nvme_delete(struct scsi_qla_host *vha) { - struct nvme_rport *rport, *trport; + struct qla_nvme_rport *qla_rport, *trport; fc_port_t *fcport; int nv_ret; if (!IS_ENABLED(CONFIG_NVME_FC)) return; - list_for_each_entry_safe(rport, trport, &vha->nvme_rport_list, list) { - fcport = rport->fcport; + list_for_each_entry_safe(qla_rport, trport, + &vha->nvme_rport_list, list) { + fcport = qla_rport->fcport; ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n", __func__, fcport); + nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); init_completion(&fcport->nvme_del_done); nvme_fc_unregister_remoteport(fcport->nvme_remote_port); - qla_nvme_wait_on_rport_del(fcport); + wait_for_completion(&fcport->nvme_del_done); } if (vha->nvme_local_port) { init_completion(&vha->nvme_del_done); + ql_log(ql_log_info, vha, 0x2116, + "unregister localport=%p\n", + vha->nvme_local_port); nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port); - if (nv_ret == 0) - ql_log(ql_log_info, vha, 0x2116, - "unregistered localport=%p\n", - vha->nvme_local_port); - else + if (nv_ret) ql_log(ql_log_info, vha, 0x2115, "Unregister of localport failed\n"); - wait_for_completion_timeout(&vha->nvme_del_done, - msecs_to_jiffies(5000)); + else + wait_for_completion(&vha->nvme_del_done); } } diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h index 7f05fa1c77db..816854ada654 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.h +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -14,6 +14,9 @@ #include "qla_def.h" +/* default dev loss time (seconds) before transport tears down ctrl */ +#define NVME_FC_DEV_LOSS_TMO 30 + #define NVME_ATIO_CMD_OFF 32 #define NVME_FIRST_PACKET_CMDLEN (64 - NVME_ATIO_CMD_OFF) #define Q2T_NVME_NUM_TAGS 2048 @@ -28,11 +31,11 @@ struct nvme_private { struct srb *sp; struct nvmefc_ls_req *fd; struct work_struct ls_work; + struct work_struct abort_work; int comp_status; }; -struct nvme_rport { - struct nvme_fc_port_info req; +struct qla_nvme_rport { struct list_head list; struct fc_port *fcport; }; @@ -142,7 +145,7 @@ struct pt_ls4_rx_unsol { void qla_nvme_register_hba(struct scsi_qla_host *); int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *); void qla_nvme_delete(struct scsi_qla_host *); -void qla_nvme_abort(struct qla_hw_data *, struct srb *sp); +void qla_nvme_abort(struct qla_hw_data *, struct srb *sp, int res); void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *, struct req_que *); void qla24xx_async_gffid_sp_done(void *, int); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index a77c33987703..872d66dd79cd 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1732,7 +1732,7 @@ iospace_error_exit: /** * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -1753,7 +1753,7 @@ qla82xx_pci_config(scsi_qla_host_t *vha) /** * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers. - * @ha: HA context + * @vha: HA context * * Returns 0 on success. */ @@ -2008,11 +2008,10 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) "MBX pointer ERROR.\n"); } -/* +/** * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. * @irq: * @dev_id: SCSI driver HA context - * @regs: * * Called by system whenever the host adapter generates an interrupt. * diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 525ac35a757b..3a2b0282df14 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -280,9 +280,8 @@ qla8044_clear_qsnt_ready(struct scsi_qla_host *vha) } /** - * * qla8044_lock_recovery - Recovers the idc_lock. - * @ha : Pointer to adapter structure + * @vha : Pointer to adapter structure * * Lock Recovery Register * 5-2 Lock recovery owner: Function ID of driver doing lock recovery, @@ -1639,10 +1638,10 @@ qla8044_set_rst_ready(struct scsi_qla_host *vha) /** * qla8044_need_reset_handler - Code to start reset sequence - * @ha: pointer to adapter structure + * @vha: pointer to adapter structure * * Note: IDC lock must be held upon entry - **/ + */ static void qla8044_need_reset_handler(struct scsi_qla_host *vha) { @@ -1859,8 +1858,8 @@ exit_update_idc_reg: /** * qla8044_need_qsnt_handler - Code to start qsnt - * @ha: pointer to adapter structure - **/ + * @vha: pointer to adapter structure + */ static void qla8044_need_qsnt_handler(struct scsi_qla_host *vha) { @@ -2031,10 +2030,10 @@ exit_error: /** * qla4_8xxx_check_temp - Check the ISP82XX temperature. - * @ha: adapter block pointer. + * @vha: adapter block pointer. * * Note: The caller should not hold the idc lock. - **/ + */ static int qla8044_check_temp(struct scsi_qla_host *vha) { @@ -2071,10 +2070,10 @@ int qla8044_read_temperature(scsi_qla_host_t *vha) /** * qla8044_check_fw_alive - Check firmware health - * @ha: Pointer to host adapter structure. + * @vha: Pointer to host adapter structure. * * Context: Interrupt - **/ + */ int qla8044_check_fw_alive(struct scsi_qla_host *vha) { diff --git a/drivers/scsi/qla2xxx/qla_nx2.h b/drivers/scsi/qla2xxx/qla_nx2.h index 83c1b7e17c80..8ba7c1db07c3 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.h +++ b/drivers/scsi/qla2xxx/qla_nx2.h @@ -23,10 +23,6 @@ #define MD_MIU_TEST_AGT_WRDATA_HI 0x410000A4 #define MD_MIU_TEST_AGT_WRDATA_ULO 0x410000B0 #define MD_MIU_TEST_AGT_WRDATA_UHI 0x410000B4 -#define MD_MIU_TEST_AGT_RDDATA_LO 0x410000A8 -#define MD_MIU_TEST_AGT_RDDATA_HI 0x410000AC -#define MD_MIU_TEST_AGT_RDDATA_ULO 0x410000B8 -#define MD_MIU_TEST_AGT_RDDATA_UHI 0x410000BC /* MIU_TEST_AGT_CTRL flags. work for SIU as well */ #define MIU_TA_CTL_WRITE_ENABLE (MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 822d22336e15..2bbf0bff0da0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -397,7 +397,6 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0; ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q]; INIT_LIST_HEAD(&ha->base_qpair->hints_list); - INIT_LIST_HEAD(&ha->base_qpair->nvme_done_list); ha->base_qpair->enable_class_2 = ql2xenableclass2; /* init qpair to this cpu. Will adjust at run time. */ qla_cpu_update(rsp->qpair, raw_smp_processor_id()); @@ -496,7 +495,7 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) return; if (IS_QLAFX00(ha)) { - if (rsp && rsp->ring) + if (rsp && rsp->ring_fx00) dma_free_coherent(&ha->pdev->dev, (rsp->length_fx00 + 1) * sizeof(request_t), rsp->ring_fx00, rsp->dma_fx00); @@ -1744,7 +1743,7 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) sp_get(sp); spin_unlock_irqrestore(qp->qp_lock_ptr, flags); - qla_nvme_abort(ha, sp); + qla_nvme_abort(ha, sp, res); spin_lock_irqsave(qp->qp_lock_ptr, flags); } else if (GET_CMD_SP(sp) && @@ -4822,12 +4821,14 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->d_id = e->u.new_sess.id; fcport->flags |= FCF_FABRIC_DEVICE; fcport->fw_login_state = DSC_LS_PLOGI_PEND; - if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) { + if (e->u.new_sess.fc4_type & FS_FC4TYPE_FCP) fcport->fc4_type = FC4_TYPE_FCP_SCSI; - } else if (e->u.new_sess.fc4_type == FC4_TYPE_NVME) { + + if (e->u.new_sess.fc4_type & FS_FC4TYPE_NVME) { fcport->fc4_type = FC4_TYPE_OTHER; fcport->fc4f_nvme = FC4_TYPE_NVME; } + memcpy(fcport->port_name, e->u.new_sess.port_name, WWN_SIZE); } else { @@ -5047,7 +5048,8 @@ qla2x00_do_work(struct scsi_qla_host *vha) e->u.logio.data); break; case QLA_EVT_GPNFT: - qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type); + qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type, + e->u.gpnft.sp); break; case QLA_EVT_GPNFT_DONE: qla24xx_async_gpnft_done(vha, e->u.iosb.sp); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index d2db86ea06b2..04458eb19d38 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -2226,6 +2226,7 @@ qla2x00_erase_flash_sector(struct qla_hw_data *ha, uint32_t addr, /** * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip. + * @ha: * @man_id: Flash manufacturer ID * @flash_id: Flash ID */ diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index b49ac85f3de2..5546ac9c3d9d 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -961,7 +961,7 @@ qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo) logo->cmd_count, res); } -static void qlt_free_session_done(struct work_struct *work) +void qlt_free_session_done(struct work_struct *work) { struct fc_port *sess = container_of(work, struct fc_port, free_work); @@ -1169,11 +1169,14 @@ void qlt_unreg_sess(struct fc_port *sess) sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; - if (sess->nvme_flag & NVME_FLAG_REGISTERED) + if (sess->nvme_flag & NVME_FLAG_REGISTERED && + !(sess->nvme_flag & NVME_FLAG_DELETING)) { + sess->nvme_flag |= NVME_FLAG_DELETING; schedule_work(&sess->nvme_del_work); - - INIT_WORK(&sess->free_work, qlt_free_session_done); - schedule_work(&sess->free_work); + } else { + INIT_WORK(&sess->free_work, qlt_free_session_done); + schedule_work(&sess->free_work); + } } EXPORT_SYMBOL(qlt_unreg_sess); @@ -2023,7 +2026,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); if (!sess) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012, - "qla_target(%d): task abort for non-existant session\n", + "qla_target(%d): task abort for non-existent session\n", vha->vp_idx); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); @@ -2866,7 +2869,6 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) uint32_t data_bytes; uint32_t dif_bytes; uint8_t bundling = 1; - uint8_t *clr_ptr; struct crc_context *crc_ctx_pkt = NULL; struct qla_hw_data *ha; struct ctio_crc2_to_fw *pkt; @@ -2995,15 +2997,11 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) /* Allocate CRC context from global pool */ crc_ctx_pkt = cmd->ctx = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); + dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); if (!crc_ctx_pkt) goto crc_queuing_error; - /* Zero out CTX area. */ - clr_ptr = (uint8_t *)crc_ctx_pkt; - memset(clr_ptr, 0, sizeof(*crc_ctx_pkt)); - crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); @@ -6292,10 +6290,11 @@ static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn, /** * qla_tgt_lport_register - register lport with external module * - * @qla_tgt_ops: Pointer for tcm_qla2xxx qla_tgt_ops - * @wwpn: Passwd FC target WWPN - * @callback: lport initialization callback for tcm_qla2xxx code * @target_lport_ptr: pointer for tcm_qla2xxx specific lport data + * @phys_wwpn: + * @npiv_wwpn: + * @npiv_wwnn: + * @callback: lport initialization callback for tcm_qla2xxx code */ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, u64 npiv_wwpn, u64 npiv_wwnn, diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index bb67b5a284a8..728ce74358e7 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -1016,7 +1016,7 @@ extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int); extern int __init qlt_init(void); extern void qlt_exit(void); extern void qlt_update_vp_map(struct scsi_qla_host *, int); - +extern void qlt_free_session_done(struct work_struct *); /* * This macro is used during early initializations when host->active_mode * is not set. Right now, ha value is ignored. diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 549bef9afddd..0c55d7057280 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.00.00.05-k" +#define QLA2XXX_VERSION "10.00.00.06-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 0 diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index bda2e64ee5ca..5d56904687b9 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1584,12 +1584,11 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, struct ql4_chap_table *chap_table; dma_addr_t chap_dma; - chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); + chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); if (chap_table == NULL) return -ENOMEM; chap_size = sizeof(struct ql4_chap_table); - memset(chap_table, 0, chap_size); if (is_qla40XX(ha)) offset = FLASH_CHAP_OFFSET | (idx * chap_size); @@ -1648,13 +1647,12 @@ int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, char *password, uint32_t chap_size = 0; dma_addr_t chap_dma; - chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); + chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); if (chap_table == NULL) { ret = -ENOMEM; goto exit_set_chap; } - memset(chap_table, 0, sizeof(struct ql4_chap_table)); if (bidi) chap_table->flags |= BIT_6; /* peer */ else diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 968bd85610f8..43f73583ef5c 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -45,6 +45,8 @@ qla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off) return NULL; } +static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, + 0x410000AC, 0x410000B8, 0x410000BC }; #define MAX_CRB_XFORM 60 static unsigned long crb_addr_xform[MAX_CRB_XFORM]; static int qla4_8xxx_crb_table_initialized; diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h index 337d9fcf6417..98fe78613eb7 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.h +++ b/drivers/scsi/qla4xxx/ql4_nx.h @@ -1022,11 +1022,4 @@ struct qla8xxx_minidump_entry_queue { #define MD_MIU_TEST_AGT_WRDATA_ULO 0x410000B0 #define MD_MIU_TEST_AGT_WRDATA_UHI 0x410000B4 -#define MD_MIU_TEST_AGT_RDDATA_LO 0x410000A8 -#define MD_MIU_TEST_AGT_RDDATA_HI 0x410000AC -#define MD_MIU_TEST_AGT_RDDATA_ULO 0x410000B8 -#define MD_MIU_TEST_AGT_RDDATA_UHI 0x410000BC - -static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, - 0x410000AC, 0x410000B8, 0x410000BC }; #endif diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index fc2c97d9a0d6..94c14ce94da2 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -843,12 +843,10 @@ static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx) uint32_t chap_size; int ret = 0; - chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); + chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); if (chap_table == NULL) return -ENOMEM; - memset(chap_table, 0, sizeof(struct ql4_chap_table)); - if (is_qla80XX(ha)) max_chap_entries = (ha->hw.flt_chap_size / 2) / sizeof(struct ql4_chap_table); diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 2c146b44d95f..ea88906d2cc5 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -157,6 +157,7 @@ static struct { { RAID_LEVEL_5, "raid5" }, { RAID_LEVEL_50, "raid50" }, { RAID_LEVEL_6, "raid6" }, + { RAID_LEVEL_JBOD, "jbod" }, }; static const char *raid_level_name(enum raid_level level) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a7e4fba724b7..4c60c260c5da 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -231,7 +231,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "(result %x)\n", cmd->result)); good_bytes = scsi_bufflen(cmd); - if (!blk_rq_is_passthrough(cmd->request)) { + if (!blk_rq_is_passthrough(cmd->request)) { int old_good_bytes = good_bytes; drv = scsi_cmd_to_driver(cmd); if (drv->done) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1cb353f18d08..9ef5e3b810f6 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6,7 +6,7 @@ * anything out of the ordinary is seen. * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * - * Copyright (C) 2001 - 2017 Douglas Gilbert + * Copyright (C) 2001 - 2018 Douglas Gilbert * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,8 +61,8 @@ #include "scsi_logging.h" /* make sure inq_product_rev string corresponds to this version */ -#define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */ -static const char *sdebug_version_date = "20171202"; +#define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */ +static const char *sdebug_version_date = "20180128"; #define MY_NAME "scsi_debug" @@ -234,6 +234,7 @@ static const char *sdebug_version_date = "20171202"; #define F_INV_OP 0x200 #define F_FAKE_RW 0x400 #define F_M_ACCESS 0x800 /* media access */ +#define F_LONG_DELAY 0x1000 #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) @@ -349,7 +350,7 @@ enum sdeb_opcode_index { SDEB_I_XDWRITEREAD = 25, /* 10 only */ SDEB_I_WRITE_BUFFER = 26, SDEB_I_WRITE_SAME = 27, /* 10, 16 */ - SDEB_I_SYNC_CACHE = 28, /* 10 only */ + SDEB_I_SYNC_CACHE = 28, /* 10, 16 */ SDEB_I_COMP_WRITE = 29, SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */ }; @@ -382,7 +383,7 @@ static const unsigned char opcode_ind_arr[256] = { /* 0x80; 0x80->0x9f: 16 byte cdbs */ 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, - 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, + 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, @@ -398,6 +399,14 @@ static const unsigned char opcode_ind_arr[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +/* + * The following "response" functions return the SCSI mid-level's 4 byte + * tuple-in-an-int. To handle commands with an IMMED bit, for a faster + * command completion, they can mask their return value with + * SDEG_RES_IMMED_MASK . + */ +#define SDEG_RES_IMMED_MASK 0x40000000 + static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); @@ -420,6 +429,7 @@ static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); /* * The following are overflow arrays for cdbs that "hit" the same index in @@ -499,6 +509,12 @@ static const struct opcode_info_t release_iarr[] = { {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; +static const struct opcode_info_t sync_cache_iarr[] = { + {0, 0x91, 0, F_LONG_DELAY | F_M_ACCESS, resp_sync_cache, NULL, + {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ +}; + /* This array is accessed via SDEB_I_* values. Make sure all are mapped, * plus the terminating elements for logic that scans this table such as @@ -536,8 +552,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, write_iarr, /* WRITE(16) */ {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */ - {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, + {0, 0x1b, 0, F_LONG_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ @@ -590,9 +606,10 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */ + {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_LONG_DELAY | F_M_ACCESS, + resp_sync_cache, sync_cache_iarr, {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, - 0, 0, 0, 0} }, + 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ @@ -616,6 +633,8 @@ static unsigned int sdebug_guard = DEF_GUARD; static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; static int sdebug_max_luns = DEF_MAX_LUNS; static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ +static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; +static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ static int sdebug_no_lun_0 = DEF_NO_LUN_0; @@ -649,7 +668,6 @@ static bool sdebug_any_injecting_opt; static bool sdebug_verbose; static bool have_dif_prot; static bool sdebug_statistics = DEF_STATISTICS; -static bool sdebug_mq_active; static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ @@ -1155,8 +1173,8 @@ static int inquiry_vpd_84(unsigned char *arr) static int inquiry_vpd_85(unsigned char *arr) { int num = 0; - const char * na1 = "https://www.kernel.org/config"; - const char * na2 = "http://www.kernel.org/log"; + const char *na1 = "https://www.kernel.org/config"; + const char *na2 = "http://www.kernel.org/log"; int plen, olen; arr[num++] = 0x1; /* lu, storage config */ @@ -1372,7 +1390,7 @@ static int inquiry_vpd_b2(unsigned char *arr) static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { unsigned char pq_pdt; - unsigned char * arr; + unsigned char *arr; unsigned char *cmd = scp->cmnd; int alloc_len, n, ret; bool have_wlun, is_disk; @@ -1523,10 +1541,10 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; -static int resp_requests(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) +static int resp_requests(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) { - unsigned char * sbuff; + unsigned char *sbuff; unsigned char *cmd = scp->cmnd; unsigned char arr[SCSI_SENSE_BUFFERSIZE]; bool dsense; @@ -1584,8 +1602,8 @@ static int resp_requests(struct scsi_cmnd * scp, return fill_from_dev_buffer(scp, arr, len); } -static int resp_start_stop(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) +static int resp_start_stop(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) { unsigned char *cmd = scp->cmnd; int power_cond, stop; @@ -1597,7 +1615,7 @@ static int resp_start_stop(struct scsi_cmnd * scp, } stop = !(cmd[4] & 1); atomic_xchg(&devip->stopped, stop); - return 0; + return (cmd[1] & 0x1) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */ } static sector_t get_sdebug_capacity(void) @@ -1612,8 +1630,8 @@ static sector_t get_sdebug_capacity(void) } #define SDEBUG_READCAP_ARR_SZ 8 -static int resp_readcap(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) +static int resp_readcap(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) { unsigned char arr[SDEBUG_READCAP_ARR_SZ]; unsigned int capac; @@ -1631,8 +1649,8 @@ static int resp_readcap(struct scsi_cmnd * scp, } #define SDEBUG_READCAP16_ARR_SZ 32 -static int resp_readcap16(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) +static int resp_readcap16(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) { unsigned char *cmd = scp->cmnd; unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; @@ -1670,11 +1688,11 @@ static int resp_readcap16(struct scsi_cmnd * scp, #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 -static int resp_report_tgtpgs(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) +static int resp_report_tgtpgs(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) { unsigned char *cmd = scp->cmnd; - unsigned char * arr; + unsigned char *arr; int host_no = devip->sdbg_host->shost->host_no; int n, ret, alen, rlen; int port_group_a, port_group_b, port_a, port_b; @@ -1926,7 +1944,7 @@ static int resp_rsup_tmfs(struct scsi_cmnd *scp, /* <<Following mode page info copied from ST318451LW>> */ -static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) +static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) { /* Read-Write Error Recovery page for mode_sense */ unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 5, 0, 0xff, 0xff}; @@ -1937,7 +1955,7 @@ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) return sizeof(err_recov_pg); } -static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) +static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) { /* Disconnect-Reconnect page for mode_sense */ unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -1948,7 +1966,7 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) return sizeof(disconnect_pg); } -static int resp_format_pg(unsigned char * p, int pcontrol, int target) +static int resp_format_pg(unsigned char *p, int pcontrol, int target) { /* Format device page for mode_sense */ unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1968,7 +1986,7 @@ static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; -static int resp_caching_pg(unsigned char * p, int pcontrol, int target) +static int resp_caching_pg(unsigned char *p, int pcontrol, int target) { /* Caching page for mode_sense */ unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -1988,7 +2006,7 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target) static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; -static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) +static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) { /* Control mode page for mode_sense */ unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -2012,7 +2030,7 @@ static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) } -static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) +static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) { /* Informational Exceptions control mode page for mode_sense */ unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; @@ -2027,7 +2045,7 @@ static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) return sizeof(iec_m_pg); } -static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) +static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) { /* SAS SSP mode page - short format for mode_sense */ unsigned char sas_sf_m_pg[] = {0x19, 0x6, 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; @@ -2039,7 +2057,7 @@ static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) } -static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, +static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, int target_dev_id) { /* SAS phy control and discover mode page for mode_sense */ unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, @@ -2072,7 +2090,7 @@ static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, return sizeof(sas_pcd_m_pg); } -static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) +static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) { /* SAS SSP shared protocol specific port mode subpage */ unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2093,7 +2111,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, unsigned char dev_spec; int alloc_len, offset, len, target_dev_id; int target = scp->device->id; - unsigned char * ap; + unsigned char *ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = scp->cmnd; bool dbd, llbaa, msense_6, is_disk, bad_pcode; @@ -2324,7 +2342,7 @@ set_mode_changed_ua: return 0; } -static int resp_temp_l_pg(unsigned char * arr) +static int resp_temp_l_pg(unsigned char *arr) { unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 0x0, 0x1, 0x3, 0x2, 0x0, 65, @@ -2334,7 +2352,7 @@ static int resp_temp_l_pg(unsigned char * arr) return sizeof(temp_l_pg); } -static int resp_ie_l_pg(unsigned char * arr) +static int resp_ie_l_pg(unsigned char *arr) { unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, }; @@ -2712,8 +2730,8 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && - (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && - ((lba + num) > OPT_MEDIUM_ERR_ADDR))) { + (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && + ((lba + num) > sdebug_medium_error_start))) { /* claim unrecoverable read error */ mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); /* set info field and valid bit for fixed descriptor */ @@ -3562,6 +3580,27 @@ static int resp_get_lba_status(struct scsi_cmnd *scp, return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); } +static int resp_sync_cache(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + u64 lba; + u32 num_blocks; + u8 *cmd = scp->cmnd; + + if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ + lba = get_unaligned_be32(cmd + 2); + num_blocks = get_unaligned_be16(cmd + 7); + } else { /* SYNCHRONIZE_CACHE(16) */ + lba = get_unaligned_be64(cmd + 2); + num_blocks = get_unaligned_be32(cmd + 10); + } + if (lba + num_blocks > sdebug_capacity) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); + return check_condition_result; + } + return (cmd[1] & 0x2) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */ +} + #define RL_BUCKET_ELEMS 8 /* Even though each pseudo target has a REPORT LUNS "well known logical unit" @@ -3727,20 +3766,13 @@ static int resp_xdwriteread_10(struct scsi_cmnd *scp, static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) { - struct sdebug_queue *sqp = sdebug_q_arr; + u32 tag = blk_mq_unique_tag(cmnd->request); + u16 hwq = blk_mq_unique_tag_to_hwq(tag); - if (sdebug_mq_active) { - u32 tag = blk_mq_unique_tag(cmnd->request); - u16 hwq = blk_mq_unique_tag_to_hwq(tag); - - if (unlikely(hwq >= submit_queues)) { - pr_warn("Unexpected hwq=%d, apply modulo\n", hwq); - hwq %= submit_queues; - } - pr_debug("tag=%u, hwq=%d\n", tag, hwq); - return sqp + hwq; - } else - return sqp; + pr_debug("tag=%#x, hwq=%d\n", tag, hwq); + if (WARN_ON_ONCE(hwq >= submit_queues)) + hwq = 0; + return sdebug_q_arr + hwq; } /* Queued (deferred) command completions converge here. */ @@ -4066,7 +4098,7 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) return SUCCESS; } -static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) +static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) { ++num_dev_resets; if (SCpnt && SCpnt->device) { @@ -4118,7 +4150,7 @@ lie: return SUCCESS; } -static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) +static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) { struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *devip; @@ -4151,9 +4183,9 @@ lie: return SUCCESS; } -static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) +static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) { - struct sdebug_host_info * sdbg_host; + struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *devip; int k = 0; @@ -4179,7 +4211,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) static void __init sdebug_build_parts(unsigned char *ramp, unsigned long store_size) { - struct partition * pp; + struct partition *pp; int starts[SDEBUG_MAX_PARTS + 2]; int sectors_per_part, num_sectors, k; int heads_by_sects, start_sec, end_sec; @@ -4262,8 +4294,13 @@ static void clear_queue_stats(void) static void setup_inject(struct sdebug_queue *sqp, struct sdebug_queued_cmd *sqcp) { - if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) + if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) { + if (sdebug_every_nth > 0) + sqcp->inj_recovered = sqcp->inj_transport + = sqcp->inj_dif + = sqcp->inj_dix = sqcp->inj_short = 0; return; + } sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); @@ -4278,7 +4315,10 @@ static void setup_inject(struct sdebug_queue *sqp, * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. */ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - int scsi_result, int delta_jiff, int ndelay) + int scsi_result, + int (*pfp)(struct scsi_cmnd *, + struct sdebug_dev_info *), + int delta_jiff, int ndelay) { unsigned long iflags; int k, num_in_q, qdepth, inject; @@ -4294,9 +4334,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } sdp = cmnd->device; - if (unlikely(sdebug_verbose && scsi_result)) - sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", - __func__, scsi_result); if (delta_jiff == 0) goto respond_in_thread; @@ -4351,7 +4388,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, sqcp = &sqp->qc_arr[k]; sqcp->a_cmnd = cmnd; cmnd->host_scribble = (unsigned char *)sqcp; - cmnd->result = scsi_result; sd_dp = sqcp->sd_dp; spin_unlock_irqrestore(&sqp->qc_lock, iflags); if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) @@ -4361,6 +4397,22 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (sd_dp == NULL) return SCSI_MLQUEUE_HOST_BUSY; } + + cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; + if (cmnd->result & SDEG_RES_IMMED_MASK) { + /* + * This is the F_DELAY_OVERR case. No delay. + */ + cmnd->result &= ~SDEG_RES_IMMED_MASK; + delta_jiff = ndelay = 0; + } + if (cmnd->result == 0 && scsi_result != 0) + cmnd->result = scsi_result; + + if (unlikely(sdebug_verbose && cmnd->result)) + sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", + __func__, cmnd->result); + if (delta_jiff > 0 || ndelay > 0) { ktime_t kt; @@ -4403,7 +4455,10 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, return 0; respond_in_thread: /* call back to mid-layer using invocation thread */ - cmnd->result = scsi_result; + cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; + cmnd->result &= ~SDEG_RES_IMMED_MASK; + if (cmnd->result == 0 && scsi_result != 0) + cmnd->result = scsi_result; cmnd->scsi_done(cmnd); return 0; } @@ -4440,6 +4495,8 @@ module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); +module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR); +module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR); module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); @@ -4497,6 +4554,8 @@ MODULE_PARM_DESC(lbprz, MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); +MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); +MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); @@ -4526,7 +4585,7 @@ MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xff #define SDEBUG_INFO_LEN 256 static char sdebug_info[SDEBUG_INFO_LEN]; -static const char * scsi_debug_info(struct Scsi_Host * shp) +static const char *scsi_debug_info(struct Scsi_Host *shp) { int k; @@ -4587,9 +4646,8 @@ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) num_host_resets); seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", dix_reads, dix_writes, dif_errors); - seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n", - TICK_NSEC / 1000, "statistics", sdebug_statistics, - sdebug_mq_active); + seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, + sdebug_statistics); seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", atomic_read(&sdebug_cmnd_count), atomic_read(&sdebug_completions), @@ -5450,7 +5508,7 @@ static void __exit scsi_debug_exit(void) device_initcall(scsi_debug_init); module_exit(scsi_debug_exit); -static void sdebug_release_adapter(struct device * dev) +static void sdebug_release_adapter(struct device *dev) { struct sdebug_host_info *sdbg_host; @@ -5588,6 +5646,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, struct sdebug_dev_info *devip; u8 *cmd = scp->cmnd; int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); + int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; int k, na; int errsts = 0; u32 flags; @@ -5612,13 +5671,8 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, n += scnprintf(b + n, sb - n, "%02x ", (u32)cmd[k]); } - if (sdebug_mq_active) - sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n", - my_name, blk_mq_unique_tag(scp->request), - b); - else - sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, - b); + sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, + blk_mq_unique_tag(scp->request), b); } if (fake_host_busy(scp)) return SCSI_MLQUEUE_HOST_BUSY; @@ -5714,20 +5768,30 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, return 0; /* ignore command: make trouble */ } if (likely(oip->pfp)) - errsts = oip->pfp(scp, devip); /* calls a resp_* function */ - else if (r_pfp) /* if leaf function ptr NULL, try the root's */ - errsts = r_pfp(scp, devip); + pfp = oip->pfp; /* calls a resp_* function */ + else + pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ fini: if (F_DELAY_OVERR & flags) - return schedule_resp(scp, devip, errsts, 0, 0); - else - return schedule_resp(scp, devip, errsts, sdebug_jdelay, + return schedule_resp(scp, devip, errsts, pfp, 0, 0); + else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) { + /* + * If any delay is active, want F_LONG_DELAY to be at least 1 + * second and if sdebug_jdelay>0 want a long delay of that + * many seconds. + */ + int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; + + jdelay = mult_frac(USER_HZ * jdelay, HZ, USER_HZ); + return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); + } else + return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, sdebug_ndelay); check_cond: - return schedule_resp(scp, devip, check_condition_result, 0, 0); + return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); err_out: - return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0); + return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); } static struct scsi_host_template sdebug_driver_template = { @@ -5757,7 +5821,7 @@ static struct scsi_host_template sdebug_driver_template = { .track_queue_depth = 1, }; -static int sdebug_driver_probe(struct device * dev) +static int sdebug_driver_probe(struct device *dev) { int error = 0; struct sdebug_host_info *sdbg_host; @@ -5782,8 +5846,7 @@ static int sdebug_driver_probe(struct device * dev) } /* Decide whether to tell scsi subsystem that we want mq */ /* Following should give the same answer for each host */ - sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1); - if (sdebug_mq_active) + if (shost_use_blk_mq(hpnt)) hpnt->nr_hw_queues = submit_queues; sdbg_host->shost = hpnt; @@ -5855,7 +5918,7 @@ static int sdebug_driver_probe(struct device * dev) return error; } -static int sdebug_driver_remove(struct device * dev) +static int sdebug_driver_remove(struct device *dev) { struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *sdbg_devinfo, *tmp; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index f3b117246d47..e5370d718058 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -175,11 +175,6 @@ static struct { {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2}, {"HITACHI", "HUS1530", "*", BLIST_NO_DIF}, {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES}, - {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ {"HP", "OPEN-", "*", BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, @@ -187,13 +182,7 @@ static struct { {"HP", "C1557A", NULL, BLIST_FORCELUN}, {"HP", "C3323-300", "4269", BLIST_NOTQ}, {"HP", "C5713A", NULL, BLIST_NOREPORTLUN}, - {"HP", "DF400", "*", BLIST_REPORTLUN2}, - {"HP", "DF500", "*", BLIST_REPORTLUN2}, - {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2}, {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ca53a5f785ee..946039117bf4 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -117,6 +117,12 @@ static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) /** * scmd_eh_abort_handler - Handle command aborts * @work: command to be aborted. + * + * Note: this function must be called only for a command that has timed out. + * Because the block layer marks a request as complete before it calls + * scsi_times_out(), a .scsi_done() call from the LLD for a command that has + * timed out do not have any effect. Hence it is safe to call + * scsi_finish_command() from this function. */ void scmd_eh_abort_handler(struct work_struct *work) @@ -1889,7 +1895,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) } return FAILED; - maybe_retry: +maybe_retry: /* we requeue for retry because the error was retryable, and * the request was not marked fast fail. Note that above, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ed79d3925860..0dfec0dedd5e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -191,7 +191,19 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) */ cmd->result = 0; if (q->mq_ops) { - scsi_mq_requeue_cmd(cmd); + /* + * Before a SCSI command is dispatched, + * get_device(&sdev->sdev_gendev) is called and the host, + * target and device busy counters are increased. Since + * requeuing a request causes these actions to be repeated and + * since scsi_device_unbusy() has already been called, + * put_device(&device->sdev_gendev) must still be called. Call + * put_device() after blk_mq_requeue_request() to avoid that + * removal of the SCSI device can start before requeueing has + * happened. + */ + blk_mq_requeue_request(cmd->request, true); + put_device(&device->sdev_gendev); return; } spin_lock_irqsave(q->queue_lock, flags); @@ -858,6 +870,17 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) /* for passthrough error may be set */ error = BLK_STS_OK; } + /* + * Another corner case: the SCSI status byte is non-zero but 'good'. + * Example: PRE-FETCH command returns SAM_STAT_CONDITION_MET when + * it is able to fit nominated LBs in its cache (and SAM_STAT_GOOD + * if it can't fit). Treat SAM_STAT_CONDITION_MET and the related + * intermediate statuses (both obsolete in SAM-4) as good. + */ + if (status_byte(result) && scsi_status_is_good(result)) { + result = 0; + error = BLK_STS_OK; + } /* * special case: failed zero length commands always need to @@ -2611,7 +2634,7 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, /* try to eat the UNIT_ATTENTION if there are enough retries */ do { result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr, - timeout, retries, NULL); + timeout, 1, NULL); if (sdev->removable && scsi_sense_valid(sshdr) && sshdr->sense_key == UNIT_ATTENTION) sdev->changed = 1; diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c deleted file mode 100644 index 489175833709..000000000000 --- a/drivers/scsi/scsi_module.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2003 Christoph Hellwig. - * Released under GPL v2. - * - * Support for old-style host templates. - * - * NOTE: Do not use this for new drivers ever. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> - -#include <scsi/scsi_host.h> - - -static int __init init_this_scsi_driver(void) -{ - struct scsi_host_template *sht = &driver_template; - struct Scsi_Host *shost; - struct list_head *l; - int error; - - if (!sht->release) { - printk(KERN_ERR - "scsi HBA driver %s didn't set a release method.\n", - sht->name); - return -EINVAL; - } - - sht->module = THIS_MODULE; - INIT_LIST_HEAD(&sht->legacy_hosts); - - sht->detect(sht); - if (list_empty(&sht->legacy_hosts)) - return -ENODEV; - - list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) { - error = scsi_add_host(shost, NULL); - if (error) - goto fail; - scsi_scan_host(shost); - } - return 0; - fail: - l = &shost->sht_legacy_list; - while ((l = l->prev) != &sht->legacy_hosts) - scsi_remove_host(list_entry(l, struct Scsi_Host, sht_legacy_list)); - return error; -} - -static void __exit exit_this_scsi_driver(void) -{ - struct scsi_host_template *sht = &driver_template; - struct Scsi_Host *shost, *s; - - list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) - scsi_remove_host(shost); - list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) - sht->release(shost); - - if (list_empty(&sht->legacy_hosts)) - return; - - printk(KERN_WARNING "%s did not call scsi_unregister\n", sht->name); - dump_stack(); - - list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) - scsi_unregister(shost); -} - -module_init(init_this_scsi_driver); -module_exit(exit_this_scsi_driver); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 7142c8be1099..1e36c9a9ad17 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1309,6 +1309,13 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) } } + if (sdev->host->hostt->sdev_groups) { + error = sysfs_create_groups(&sdev->sdev_gendev.kobj, + sdev->host->hostt->sdev_groups); + if (error) + return error; + } + scsi_autopm_put_device(sdev); return error; } @@ -1348,6 +1355,10 @@ void __scsi_remove_device(struct scsi_device *sdev) if (res != 0) return; + if (sdev->host->hostt->sdev_groups) + sysfs_remove_groups(&sdev->sdev_gendev.kobj, + sdev->host->hostt->sdev_groups); + bsg_unregister_queue(sdev->request_queue); device_unregister(&sdev->sdev_dev); transport_remove_device(dev); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 871ea582029e..2ca150b16764 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -822,11 +822,11 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) * fails, the device won't let us write to the echo buffer * so just return failure */ - const char spi_test_unit_ready[] = { + static const char spi_test_unit_ready[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 }; - const char spi_read_buffer_descriptor[] = { + static const char spi_read_buffer_descriptor[] = { READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0 }; diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 89cf4498f535..41df75eea57b 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -515,7 +515,8 @@ static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp) * sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones * @sdkp: disk used * @buf: report reply buffer - * @seq_zone_bitamp: bitmap of sequential zones to set + * @buflen: length of @buf + * @seq_zones_bitmap: bitmap of sequential zones to set * * Parse reported zone descriptors in @buf to identify sequential zones and * set the reported zone bit in @seq_zones_bitmap accordingly. diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 10c94011c8a8..592b6dbf8b35 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -40,11 +40,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "1.1.2-126" +#define DRIVER_VERSION "1.1.4-115" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 1 -#define DRIVER_RELEASE 2 -#define DRIVER_REVISION 126 +#define DRIVER_RELEASE 4 +#define DRIVER_REVISION 115 #define DRIVER_NAME "Microsemi PQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" @@ -3898,29 +3898,6 @@ static int pqi_validate_device_capability(struct pqi_ctrl_info *ctrl_info) return 0; } -static int pqi_delete_operational_queue(struct pqi_ctrl_info *ctrl_info, - bool inbound_queue, u16 queue_id) -{ - struct pqi_general_admin_request request; - struct pqi_general_admin_response response; - - memset(&request, 0, sizeof(request)); - request.header.iu_type = PQI_REQUEST_IU_GENERAL_ADMIN; - put_unaligned_le16(PQI_GENERAL_ADMIN_IU_LENGTH, - &request.header.iu_length); - if (inbound_queue) - request.function_code = - PQI_GENERAL_ADMIN_FUNCTION_DELETE_IQ; - else - request.function_code = - PQI_GENERAL_ADMIN_FUNCTION_DELETE_OQ; - put_unaligned_le16(queue_id, - &request.data.delete_operational_queue.queue_id); - - return pqi_submit_admin_request_synchronous(ctrl_info, &request, - &response); -} - static int pqi_create_event_queue(struct pqi_ctrl_info *ctrl_info) { int rc; @@ -4038,7 +4015,7 @@ static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info, if (rc) { dev_err(&ctrl_info->pci_dev->dev, "error creating inbound AIO queue\n"); - goto delete_inbound_queue_raid; + return rc; } queue_group->iq_pi[AIO_PATH] = ctrl_info->iomem_base + @@ -4066,7 +4043,7 @@ static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info, if (rc) { dev_err(&ctrl_info->pci_dev->dev, "error changing queue property\n"); - goto delete_inbound_queue_aio; + return rc; } /* @@ -4096,7 +4073,7 @@ static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info, if (rc) { dev_err(&ctrl_info->pci_dev->dev, "error creating outbound queue\n"); - goto delete_inbound_queue_aio; + return rc; } queue_group->oq_ci = ctrl_info->iomem_base + @@ -4105,16 +4082,6 @@ static int pqi_create_queue_group(struct pqi_ctrl_info *ctrl_info, &response.data.create_operational_oq.oq_ci_offset); return 0; - -delete_inbound_queue_aio: - pqi_delete_operational_queue(ctrl_info, true, - queue_group->iq_id[AIO_PATH]); - -delete_inbound_queue_raid: - pqi_delete_operational_queue(ctrl_info, true, - queue_group->iq_id[RAID_PATH]); - - return rc; } static int pqi_create_queues(struct pqi_ctrl_info *ctrl_info) @@ -6797,6 +6764,14 @@ static __maybe_unused int pqi_resume(struct pci_dev *pci_dev) static const struct pci_device_id pqi_pci_id_table[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x105b, 0x1211) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x105b, 0x1321) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x152d, 0x8a22) }, { @@ -6817,6 +6792,38 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x8460) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x8461) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0xf460) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0xf461) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0045) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0046) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0047) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x0048) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x0110) }, { @@ -6917,6 +6924,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x1282) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x1300) }, { diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index d50c5ed8f428..0b1421cdf8a0 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -210,7 +210,7 @@ static int esp_sun3x_probe(struct platform_device *dev) esp = shost_priv(host); esp->host = host; - esp->dev = dev; + esp->dev = &dev->dev; esp->ops = &sun3x_esp_ops; res = platform_get_resource(dev, IORESOURCE_MEM, 0); diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c deleted file mode 100644 index 5bdcbe8fa958..000000000000 --- a/drivers/scsi/sym53c416.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * sym53c416.c - * Low-level SCSI driver for sym53c416 chip. - * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) - * - * Changes : - * - * Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking - * Alan Cox <alan@lxorguk.ukuu.org.uk> : Cleaned up code formatting - * Fixed an irq locking bug - * Added ISAPnP support - * Bjoern A. Zeeb <bzeeb@zabbadoz.net> : Initial irq locking updates - * Added another card with ISAPnP support - * - * LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>] - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/blkdev.h> -#include <linux/isapnp.h> -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "sym53c416.h" - -#define VERSION_STRING "Version 1.0.0-ac" - -#define TC_LOW 0x00 /* Transfer counter low */ -#define TC_MID 0x01 /* Transfer counter mid */ -#define SCSI_FIFO 0x02 /* SCSI FIFO register */ -#define COMMAND_REG 0x03 /* Command Register */ -#define STATUS_REG 0x04 /* Status Register (READ) */ -#define DEST_BUS_ID 0x04 /* Destination Bus ID (WRITE) */ -#define INT_REG 0x05 /* Interrupt Register (READ) */ -#define TOM 0x05 /* Time out multiplier (WRITE) */ -#define STP 0x06 /* Synchronous Transfer period */ -#define SYNC_OFFSET 0x07 /* Synchronous Offset */ -#define CONF_REG_1 0x08 /* Configuration register 1 */ -#define CONF_REG_2 0x0B /* Configuration register 2 */ -#define CONF_REG_3 0x0C /* Configuration register 3 */ -#define CONF_REG_4 0x0D /* Configuration register 4 */ -#define TC_HIGH 0x0E /* Transfer counter high */ -#define PIO_FIFO_1 0x10 /* PIO FIFO register 1 */ -#define PIO_FIFO_2 0x11 /* PIO FIFO register 2 */ -#define PIO_FIFO_3 0x12 /* PIO FIFO register 3 */ -#define PIO_FIFO_4 0x13 /* PIO FIFO register 4 */ -#define PIO_FIFO_CNT 0x14 /* PIO FIFO count */ -#define PIO_INT_REG 0x15 /* PIO interrupt register */ -#define CONF_REG_5 0x16 /* Configuration register 5 */ -#define FEATURE_EN 0x1D /* Feature Enable register */ - -/* Configuration register 1 entries: */ -/* Bits 2-0: SCSI ID of host adapter */ -#define SCM 0x80 /* Slow Cable Mode */ -#define SRID 0x40 /* SCSI Reset Interrupt Disable */ -#define PTM 0x20 /* Parity Test Mode */ -#define EPC 0x10 /* Enable Parity Checking */ -#define CTME 0x08 /* Special Test Mode */ - -/* Configuration register 2 entries: */ -#define FE 0x40 /* Features Enable */ -#define SCSI2 0x08 /* SCSI 2 Enable */ -#define TBPA 0x04 /* Target Bad Parity Abort */ - -/* Configuration register 3 entries: */ -#define IDMRC 0x80 /* ID Message Reserved Check */ -#define QTE 0x40 /* Queue Tag Enable */ -#define CDB10 0x20 /* Command Descriptor Block 10 */ -#define FSCSI 0x10 /* FastSCSI */ -#define FCLK 0x08 /* FastClock */ - -/* Configuration register 4 entries: */ -#define RBS 0x08 /* Register bank select */ -#define EAN 0x04 /* Enable Active Negotiation */ - -/* Configuration register 5 entries: */ -#define LPSR 0x80 /* Lower Power SCSI Reset */ -#define IE 0x20 /* Interrupt Enable */ -#define LPM 0x02 /* Low Power Mode */ -#define WSE0 0x01 /* 0WS Enable */ - -/* Interrupt register entries: */ -#define SRST 0x80 /* SCSI Reset */ -#define ILCMD 0x40 /* Illegal Command */ -#define DIS 0x20 /* Disconnect */ -#define BS 0x10 /* Bus Service */ -#define FC 0x08 /* Function Complete */ -#define RESEL 0x04 /* Reselected */ -#define SI 0x03 /* Selection Interrupt */ - -/* Status Register Entries: */ -#define SCI 0x80 /* SCSI Core Int */ -#define GE 0x40 /* Gross Error */ -#define PE 0x20 /* Parity Error */ -#define TC 0x10 /* Terminal Count */ -#define VGC 0x08 /* Valid Group Code */ -#define PHBITS 0x07 /* Phase bits */ - -/* PIO Interrupt Register Entries: */ -#define SCI 0x80 /* SCSI Core Int */ -#define PFI 0x40 /* PIO FIFO Interrupt */ -#define FULL 0x20 /* PIO FIFO Full */ -#define EMPTY 0x10 /* PIO FIFO Empty */ -#define CE 0x08 /* Collision Error */ -#define OUE 0x04 /* Overflow / Underflow error */ -#define FIE 0x02 /* Full Interrupt Enable */ -#define EIE 0x01 /* Empty Interrupt Enable */ - -/* SYM53C416 SCSI phases (lower 3 bits of SYM53C416_STATUS_REG) */ -#define PHASE_DATA_OUT 0x00 -#define PHASE_DATA_IN 0x01 -#define PHASE_COMMAND 0x02 -#define PHASE_STATUS 0x03 -#define PHASE_RESERVED_1 0x04 -#define PHASE_RESERVED_2 0x05 -#define PHASE_MESSAGE_OUT 0x06 -#define PHASE_MESSAGE_IN 0x07 - -/* SYM53C416 core commands */ -#define NOOP 0x00 -#define FLUSH_FIFO 0x01 -#define RESET_CHIP 0x02 -#define RESET_SCSI_BUS 0x03 -#define DISABLE_SEL_RESEL 0x45 -#define RESEL_SEQ 0x40 -#define SEL_WITHOUT_ATN_SEQ 0x41 -#define SEL_WITH_ATN_SEQ 0x42 -#define SEL_WITH_ATN_AND_STOP_SEQ 0x43 -#define ENABLE_SEL_RESEL 0x44 -#define SEL_WITH_ATN3_SEQ 0x46 -#define RESEL3_SEQ 0x47 -#define SND_MSG 0x20 -#define SND_STAT 0x21 -#define SND_DATA 0x22 -#define DISCONNECT_SEQ 0x23 -#define TERMINATE_SEQ 0x24 -#define TARGET_COMM_COMPLETE_SEQ 0x25 -#define DISCONN 0x27 -#define RECV_MSG_SEQ 0x28 -#define RECV_CMD 0x29 -#define RECV_DATA 0x2A -#define RECV_CMD_SEQ 0x2B -#define TARGET_ABORT_PIO 0x04 -#define TRANSFER_INFORMATION 0x10 -#define INIT_COMM_COMPLETE_SEQ 0x11 -#define MSG_ACCEPTED 0x12 -#define TRANSFER_PAD 0x18 -#define SET_ATN 0x1A -#define RESET_ATN 0x1B -#define ILLEGAL 0xFF - -#define PIO_MODE 0x80 - -#define IO_RANGE 0x20 /* 0x00 - 0x1F */ -#define ID "sym53c416" /* Attention: copied to the sym53c416.h */ -#define PIO_SIZE 128 /* Size of PIO fifo is 128 bytes */ - -#define READ_TIMEOUT 150 -#define WRITE_TIMEOUT 150 - -#ifdef MODULE - -#define sym53c416_base sym53c416 -#define sym53c416_base_1 sym53c416_1 -#define sym53c416_base_2 sym53c416_2 -#define sym53c416_base_3 sym53c416_3 - -static unsigned int sym53c416_base[2]; -static unsigned int sym53c416_base_1[2]; -static unsigned int sym53c416_base_2[2]; -static unsigned int sym53c416_base_3[2]; - -#endif - -#define MAXHOSTS 4 - -#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer))) - -enum phases -{ - idle, - data_out, - data_in, - command_ph, - status_ph, - message_out, - message_in -}; - -typedef struct -{ - int base; - int irq; - int scsi_id; -} host; - -static host hosts[MAXHOSTS] = { - {0, 0, SYM53C416_SCSI_ID}, - {0, 0, SYM53C416_SCSI_ID}, - {0, 0, SYM53C416_SCSI_ID}, - {0, 0, SYM53C416_SCSI_ID} - }; - -static int host_index = 0; -static char info[120]; -static Scsi_Cmnd *current_command = NULL; -static int fastpio = 1; - -static int probeaddrs[] = {0x200, 0x220, 0x240, 0}; - -static void sym53c416_set_transfer_counter(int base, unsigned int len) -{ - /* Program Transfer Counter */ - outb(len & 0x0000FF, base + TC_LOW); - outb((len & 0x00FF00) >> 8, base + TC_MID); - outb((len & 0xFF0000) >> 16, base + TC_HIGH); -} - -static DEFINE_SPINLOCK(sym53c416_lock); - -/* Returns the number of bytes read */ -static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len) -{ - unsigned int orig_len = len; - unsigned long flags = 0; - unsigned int bytes_left; - unsigned long i; - int timeout = READ_TIMEOUT; - - /* Do transfer */ - spin_lock_irqsave(&sym53c416_lock, flags); - while(len && timeout) - { - bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */ - if(fastpio && bytes_left > 3) - { - insl(base + PIO_FIFO_1, buffer, bytes_left >> 2); - buffer += bytes_left & 0xFC; - len -= bytes_left & 0xFC; - } - else if(bytes_left > 0) - { - len -= bytes_left; - for(; bytes_left > 0; bytes_left--) - *(buffer++) = inb(base + PIO_FIFO_1); - } - else - { - i = jiffies + timeout; - spin_unlock_irqrestore(&sym53c416_lock, flags); - while(time_before(jiffies, i) && (inb(base + PIO_INT_REG) & EMPTY) && timeout) - if(inb(base + PIO_INT_REG) & SCI) - timeout = 0; - spin_lock_irqsave(&sym53c416_lock, flags); - if(inb(base + PIO_INT_REG) & EMPTY) - timeout = 0; - } - } - spin_unlock_irqrestore(&sym53c416_lock, flags); - return orig_len - len; -} - -/* Returns the number of bytes written */ -static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len) -{ - unsigned int orig_len = len; - unsigned long flags = 0; - unsigned int bufferfree; - unsigned long i; - unsigned int timeout = WRITE_TIMEOUT; - - /* Do transfer */ - spin_lock_irqsave(&sym53c416_lock, flags); - while(len && timeout) - { - bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT); - if(bufferfree > len) - bufferfree = len; - if(fastpio && bufferfree > 3) - { - outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2); - buffer += bufferfree & 0xFC; - len -= bufferfree & 0xFC; - } - else if(bufferfree > 0) - { - len -= bufferfree; - for(; bufferfree > 0; bufferfree--) - outb(*(buffer++), base + PIO_FIFO_1); - } - else - { - i = jiffies + timeout; - spin_unlock_irqrestore(&sym53c416_lock, flags); - while(time_before(jiffies, i) && (inb(base + PIO_INT_REG) & FULL) && timeout) - ; - spin_lock_irqsave(&sym53c416_lock, flags); - if(inb(base + PIO_INT_REG) & FULL) - timeout = 0; - } - } - spin_unlock_irqrestore(&sym53c416_lock, flags); - return orig_len - len; -} - -static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id) -{ - struct Scsi_Host *dev = dev_id; - int base = dev->io_port; - int i; - unsigned long flags = 0; - unsigned char status_reg, pio_int_reg, int_reg; - struct scatterlist *sg; - unsigned int tot_trans = 0; - - spin_lock_irqsave(dev->host_lock,flags); - status_reg = inb(base + STATUS_REG); - pio_int_reg = inb(base + PIO_INT_REG); - int_reg = inb(base + INT_REG); - spin_unlock_irqrestore(dev->host_lock, flags); - - /* First, we handle error conditions */ - if(int_reg & SCI) /* SCSI Reset */ - { - printk(KERN_DEBUG "sym53c416: Reset received\n"); - current_command->SCp.phase = idle; - current_command->result = DID_RESET << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(int_reg & ILCMD) /* Illegal Command */ - { - printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG)); - current_command->SCp.phase = idle; - current_command->result = DID_ERROR << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(status_reg & GE) /* Gross Error */ - { - printk(KERN_WARNING "sym53c416: Controller reports gross error.\n"); - current_command->SCp.phase = idle; - current_command->result = DID_ERROR << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(status_reg & PE) /* Parity Error */ - { - printk(KERN_WARNING "sym53c416:SCSI parity error.\n"); - current_command->SCp.phase = idle; - current_command->result = DID_PARITY << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(pio_int_reg & (CE | OUE)) - { - printk(KERN_WARNING "sym53c416: PIO interrupt error.\n"); - current_command->SCp.phase = idle; - current_command->result = DID_ERROR << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(int_reg & DIS) /* Disconnect */ - { - if(current_command->SCp.phase != message_in) - current_command->result = DID_NO_CONNECT << 16; - else - current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16); - current_command->SCp.phase = idle; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - /* Now we handle SCSI phases */ - - switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */ - { - case PHASE_DATA_OUT: - { - if(int_reg & BS) - { - current_command->SCp.phase = data_out; - outb(FLUSH_FIFO, base + COMMAND_REG); - sym53c416_set_transfer_counter(base, - scsi_bufflen(current_command)); - outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); - - scsi_for_each_sg(current_command, - sg, scsi_sg_count(current_command), i) { - tot_trans += sym53c416_write(base, - SG_ADDRESS(sg), - sg->length); - } - if(tot_trans < current_command->underflow) - printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow); - } - break; - } - - case PHASE_DATA_IN: - { - if(int_reg & BS) - { - current_command->SCp.phase = data_in; - outb(FLUSH_FIFO, base + COMMAND_REG); - sym53c416_set_transfer_counter(base, - scsi_bufflen(current_command)); - - outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); - - scsi_for_each_sg(current_command, - sg, scsi_sg_count(current_command), i) { - tot_trans += sym53c416_read(base, - SG_ADDRESS(sg), - sg->length); - } - if(tot_trans < current_command->underflow) - printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow); - } - break; - } - - case PHASE_COMMAND: - { - current_command->SCp.phase = command_ph; - printk(KERN_ERR "sym53c416: Unknown interrupt in command phase.\n"); - break; - } - - case PHASE_STATUS: - { - current_command->SCp.phase = status_ph; - outb(FLUSH_FIFO, base + COMMAND_REG); - outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG); - break; - } - - case PHASE_RESERVED_1: - case PHASE_RESERVED_2: - { - printk(KERN_ERR "sym53c416: Reserved phase occurred.\n"); - break; - } - - case PHASE_MESSAGE_OUT: - { - current_command->SCp.phase = message_out; - outb(SET_ATN, base + COMMAND_REG); - outb(MSG_ACCEPTED, base + COMMAND_REG); - break; - } - - case PHASE_MESSAGE_IN: - { - current_command->SCp.phase = message_in; - current_command->SCp.Status = inb(base + SCSI_FIFO); - current_command->SCp.Message = inb(base + SCSI_FIFO); - if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT) - outb(SET_ATN, base + COMMAND_REG); - outb(MSG_ACCEPTED, base + COMMAND_REG); - break; - } - } -out: - return IRQ_HANDLED; -} - -static void sym53c416_init(int base, int scsi_id) -{ - outb(RESET_CHIP, base + COMMAND_REG); - outb(NOOP, base + COMMAND_REG); - outb(0x99, base + TOM); /* Time out of 250 ms */ - outb(0x05, base + STP); - outb(0x00, base + SYNC_OFFSET); - outb(EPC | scsi_id, base + CONF_REG_1); - outb(FE | SCSI2 | TBPA, base + CONF_REG_2); - outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3); - outb(0x83 | EAN, base + CONF_REG_4); - outb(IE | WSE0, base + CONF_REG_5); - outb(0, base + FEATURE_EN); -} - -static int sym53c416_probeirq(int base, int scsi_id) -{ - int irq, irqs; - unsigned long i; - - /* Clear interrupt register */ - inb(base + INT_REG); - /* Start probing for irq's */ - irqs = probe_irq_on(); - /* Reinit chip */ - sym53c416_init(base, scsi_id); - /* Cause interrupt */ - outb(NOOP, base + COMMAND_REG); - outb(ILLEGAL, base + COMMAND_REG); - outb(0x07, base + DEST_BUS_ID); - outb(0x00, base + DEST_BUS_ID); - /* Wait for interrupt to occur */ - i = jiffies + 20; - while(time_before(jiffies, i) && !(inb(base + STATUS_REG) & SCI)) - barrier(); - if(time_before_eq(i, jiffies)) /* timed out */ - return 0; - /* Get occurred irq */ - irq = probe_irq_off(irqs); - sym53c416_init(base, scsi_id); - return irq; -} - -/* Setup: sym53c416=base,irq */ -void sym53c416_setup(char *str, int *ints) -{ - int i; - - if(host_index >= MAXHOSTS) - { - printk(KERN_WARNING "sym53c416: Too many hosts defined\n"); - return; - } - if(ints[0] < 1 || ints[0] > 2) - { - printk(KERN_ERR "sym53c416: Wrong number of parameters:\n"); - printk(KERN_ERR "sym53c416: usage: sym53c416=<base>[,<irq>]\n"); - return; - } - for(i = 0; i < host_index && i >= 0; i++) - if(hosts[i].base == ints[1]) - i = -2; - if(i >= 0) - { - hosts[host_index].base = ints[1]; - hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0; - host_index++; - } -} - -static int sym53c416_test(int base) -{ - outb(RESET_CHIP, base + COMMAND_REG); - outb(NOOP, base + COMMAND_REG); - if(inb(base + COMMAND_REG) != NOOP) - return 0; - if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF) - return 0; - if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY) - return 0; - return 1; -} - - -static struct isapnp_device_id id_table[] = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4161), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 }, - { ISAPNP_DEVICE_SINGLE_END } -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); - -static void sym53c416_probe(void) -{ - int *base = probeaddrs; - int ints[2]; - - ints[0] = 1; - for(; *base; base++) { - if (request_region(*base, IO_RANGE, ID)) { - if (sym53c416_test(*base)) { - ints[1] = *base; - sym53c416_setup(NULL, ints); - } - release_region(*base, IO_RANGE); - } - } -} - -int __init sym53c416_detect(struct scsi_host_template *tpnt) -{ - unsigned long flags; - struct Scsi_Host * shpnt = NULL; - int i; - int count; - struct pnp_dev *idev = NULL; - -#ifdef MODULE - int ints[3]; - - ints[0] = 2; - if(sym53c416_base[0]) - { - ints[1] = sym53c416_base[0]; - ints[2] = sym53c416_base[1]; - sym53c416_setup(NULL, ints); - } - if(sym53c416_base_1[0]) - { - ints[1] = sym53c416_base_1[0]; - ints[2] = sym53c416_base_1[1]; - sym53c416_setup(NULL, ints); - } - if(sym53c416_base_2[0]) - { - ints[1] = sym53c416_base_2[0]; - ints[2] = sym53c416_base_2[1]; - sym53c416_setup(NULL, ints); - } - if(sym53c416_base_3[0]) - { - ints[1] = sym53c416_base_3[0]; - ints[2] = sym53c416_base_3[1]; - sym53c416_setup(NULL, ints); - } -#endif - printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING); - - for (i=0; id_table[i].vendor != 0; i++) { - while((idev=pnp_find_dev(NULL, id_table[i].vendor, - id_table[i].function, idev))!=NULL) - { - int i[3]; - - if(pnp_device_attach(idev)<0) - { - printk(KERN_WARNING "sym53c416: unable to attach PnP device.\n"); - continue; - } - if(pnp_activate_dev(idev) < 0) - { - printk(KERN_WARNING "sym53c416: unable to activate PnP device.\n"); - pnp_device_detach(idev); - continue; - - } - - i[0] = 2; - i[1] = pnp_port_start(idev, 0); - i[2] = pnp_irq(idev, 0); - - printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n", - i[1], i[2]); - sym53c416_setup(NULL, i); - } - } - sym53c416_probe(); - - /* Now we register and set up each host adapter found... */ - for(count = 0, i = 0; i < host_index; i++) { - if (!request_region(hosts[i].base, IO_RANGE, ID)) - continue; - if (!sym53c416_test(hosts[i].base)) { - printk(KERN_WARNING "No sym53c416 found at address 0x%03x\n", hosts[i].base); - goto fail_release_region; - } - - /* We don't have an irq yet, so we should probe for one */ - if (!hosts[i].irq) - hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id); - if (!hosts[i].irq) - goto fail_release_region; - - shpnt = scsi_register(tpnt, 0); - if (!shpnt) - goto fail_release_region; - /* Request for specified IRQ */ - if (request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt)) - goto fail_free_host; - - spin_lock_irqsave(&sym53c416_lock, flags); - shpnt->unique_id = hosts[i].base; - shpnt->io_port = hosts[i].base; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = hosts[i].irq; - shpnt->this_id = hosts[i].scsi_id; - sym53c416_init(hosts[i].base, hosts[i].scsi_id); - count++; - spin_unlock_irqrestore(&sym53c416_lock, flags); - continue; - - fail_free_host: - scsi_unregister(shpnt); - fail_release_region: - release_region(hosts[i].base, IO_RANGE); - } - return count; -} - -const char *sym53c416_info(struct Scsi_Host *SChost) -{ - int i; - int base = SChost->io_port; - int irq = SChost->irq; - int scsi_id = 0; - int rev = inb(base + TC_HIGH); - - for(i = 0; i < host_index; i++) - if(hosts[i].base == base) - scsi_id = hosts[i].scsi_id; - sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow"); - return info; -} - -static int sym53c416_queuecommand_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) -{ - int base; - unsigned long flags = 0; - int i; - - /* Store base register as we can have more than one controller in the system */ - base = SCpnt->device->host->io_port; - current_command = SCpnt; /* set current command */ - current_command->scsi_done = done; /* set ptr to done function */ - current_command->SCp.phase = command_ph; /* currect phase is the command phase */ - current_command->SCp.Status = 0; - current_command->SCp.Message = 0; - - spin_lock_irqsave(&sym53c416_lock, flags); - outb(scmd_id(SCpnt), base + DEST_BUS_ID); /* Set scsi id target */ - outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */ - /* Write SCSI command into the SCSI fifo */ - for(i = 0; i < SCpnt->cmd_len; i++) - outb(SCpnt->cmnd[i], base + SCSI_FIFO); - /* Start selection sequence */ - outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG); - /* Now an interrupt will be generated which we will catch in out interrupt routine */ - spin_unlock_irqrestore(&sym53c416_lock, flags); - return 0; -} - -DEF_SCSI_QCMD(sym53c416_queuecommand) - -static int sym53c416_host_reset(Scsi_Cmnd *SCpnt) -{ - int base; - int scsi_id = -1; - int i; - unsigned long flags; - - spin_lock_irqsave(&sym53c416_lock, flags); - - /* printk("sym53c416_reset\n"); */ - base = SCpnt->device->host->io_port; - /* search scsi_id - fixme, we shouldn't need to iterate for this! */ - for(i = 0; i < host_index && scsi_id == -1; i++) - if(hosts[i].base == base) - scsi_id = hosts[i].scsi_id; - outb(RESET_CHIP, base + COMMAND_REG); - outb(NOOP | PIO_MODE, base + COMMAND_REG); - outb(RESET_SCSI_BUS, base + COMMAND_REG); - sym53c416_init(base, scsi_id); - - spin_unlock_irqrestore(&sym53c416_lock, flags); - return SUCCESS; -} - -static int sym53c416_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - return 0; -} - -static int sym53c416_bios_param(struct scsi_device *sdev, - struct block_device *dev, - sector_t capacity, int *ip) -{ - int size; - - size = capacity; - ip[0] = 64; /* heads */ - ip[1] = 32; /* sectors */ - if((ip[2] = size >> 11) > 1024) /* cylinders, test for big disk */ - { - ip[0] = 255; /* heads */ - ip[1] = 63; /* sectors */ - ip[2] = size / (255 * 63); /* cylinders */ - } - return 0; -} - -/* Loadable module support */ -#ifdef MODULE - -MODULE_AUTHOR("Lieven Willems"); -MODULE_LICENSE("GPL"); - -module_param_array(sym53c416, uint, NULL, 0); -module_param_array(sym53c416_1, uint, NULL, 0); -module_param_array(sym53c416_2, uint, NULL, 0); -module_param_array(sym53c416_3, uint, NULL, 0); - -#endif - -static struct scsi_host_template driver_template = { - .proc_name = "sym53c416", - .name = "Symbios Logic 53c416", - .detect = sym53c416_detect, - .info = sym53c416_info, - .queuecommand = sym53c416_queuecommand, - .eh_host_reset_handler =sym53c416_host_reset, - .release = sym53c416_release, - .bios_param = sym53c416_bios_param, - .can_queue = 1, - .this_id = SYM53C416_SCSI_ID, - .sg_tablesize = 32, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h deleted file mode 100644 index 387de5d80a70..000000000000 --- a/drivers/scsi/sym53c416.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * sym53c416.h - * - * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#ifndef _SYM53C416_H -#define _SYM53C416_H - -#include <linux/types.h> - -#define SYM53C416_SCSI_ID 7 - -static int sym53c416_detect(struct scsi_host_template *); -static const char *sym53c416_info(struct Scsi_Host *); -static int sym53c416_release(struct Scsi_Host *); -static int sym53c416_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int sym53c416_host_reset(Scsi_Cmnd *); -static int sym53c416_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static void sym53c416_setup(char *str, int *ints); -#endif diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 9310c6c83041..918f5791202d 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o -obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o +obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o +ufshcd-core-objs := ufshcd.o ufs-sysfs.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c index 325d5e14fc0d..2f41722a8c28 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pci.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c @@ -51,7 +51,7 @@ static int tc_dwc_g210_pci_runtime_idle(struct device *dev) return ufshcd_runtime_idle(dev_get_drvdata(dev)); } -/** +/* * struct ufs_hba_dwc_vops - UFS DWC specific variant operations */ static struct ufs_hba_variant_ops tc_dwc_g210_pci_hba_vops = { @@ -71,7 +71,7 @@ static void tc_dwc_g210_pci_shutdown(struct pci_dev *pdev) /** * tc_dwc_g210_pci_remove - de-allocate PCI/SCSI host and host memory space * data structure memory - * @pdev - pointer to PCI handle + * @pdev: pointer to PCI handle */ static void tc_dwc_g210_pci_remove(struct pci_dev *pdev) { diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c index 2d3f5270f875..6dfe5a9206e9 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c @@ -20,7 +20,7 @@ #include "ufshcd-dwc.h" #include "tc-dwc-g210.h" -/** +/* * UFS DWC specific variant operations */ static struct ufs_hba_variant_ops tc_dwc_g210_20bit_pltfm_hba_vops = { diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c new file mode 100644 index 000000000000..8d9332bb7d0c --- /dev/null +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -0,0 +1,817 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Western Digital Corporation + +#include <linux/err.h> +#include <linux/string.h> +#include <linux/bitfield.h> +#include <asm/unaligned.h> + +#include "ufs.h" +#include "ufs-sysfs.h" + +static const char *ufschd_uic_link_state_to_string( + enum uic_link_state state) +{ + switch (state) { + case UIC_LINK_OFF_STATE: return "OFF"; + case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; + case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; + default: return "UNKNOWN"; + } +} + +static const char *ufschd_ufs_dev_pwr_mode_to_string( + enum ufs_dev_pwr_mode state) +{ + switch (state) { + case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; + case UFS_SLEEP_PWR_MODE: return "SLEEP"; + case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; + default: return "UNKNOWN"; + } +} + +static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, + bool rpm) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned long flags, value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value >= UFS_PM_LVL_MAX) + return -EINVAL; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (rpm) + hba->rpm_lvl = value; + else + hba->spm_lvl = value; + spin_unlock_irqrestore(hba->host->host_lock, flags); + return count; +} + +static ssize_t rpm_lvl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", hba->rpm_lvl); +} + +static ssize_t rpm_lvl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, true); +} + +static ssize_t rpm_target_dev_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[hba->rpm_lvl].dev_state)); +} + +static ssize_t rpm_target_link_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[hba->rpm_lvl].link_state)); +} + +static ssize_t spm_lvl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", hba->spm_lvl); +} + +static ssize_t spm_lvl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, false); +} + +static ssize_t spm_target_dev_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ufschd_ufs_dev_pwr_mode_to_string( + ufs_pm_lvl_states[hba->spm_lvl].dev_state)); +} + +static ssize_t spm_target_link_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ufschd_uic_link_state_to_string( + ufs_pm_lvl_states[hba->spm_lvl].link_state)); +} + +static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) +{ + unsigned long flags; + + if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + return; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (hba->ahit == ahit) + goto out_unlock; + hba->ahit = ahit; + if (!pm_runtime_suspended(hba->dev)) + ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); +out_unlock: + spin_unlock_irqrestore(hba->host->host_lock, flags); +} + +/* Convert Auto-Hibernate Idle Timer register value to microseconds */ +static int ufshcd_ahit_to_us(u32 ahit) +{ + int timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, ahit); + int scale = FIELD_GET(UFSHCI_AHIBERN8_SCALE_MASK, ahit); + + for (; scale > 0; --scale) + timer *= UFSHCI_AHIBERN8_SCALE_FACTOR; + + return timer; +} + +/* Convert microseconds to Auto-Hibernate Idle Timer register value */ +static u32 ufshcd_us_to_ahit(unsigned int timer) +{ + unsigned int scale; + + for (scale = 0; timer > UFSHCI_AHIBERN8_TIMER_MASK; ++scale) + timer /= UFSHCI_AHIBERN8_SCALE_FACTOR; + + return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) | + FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale); +} + +static ssize_t auto_hibern8_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + return -EOPNOTSUPP; + + return snprintf(buf, PAGE_SIZE, "%d\n", ufshcd_ahit_to_us(hba->ahit)); +} + +static ssize_t auto_hibern8_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned int timer; + + if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + return -EOPNOTSUPP; + + if (kstrtouint(buf, 0, &timer)) + return -EINVAL; + + if (timer > UFSHCI_AHIBERN8_MAX) + return -EINVAL; + + ufshcd_auto_hibern8_update(hba, ufshcd_us_to_ahit(timer)); + + return count; +} + +static DEVICE_ATTR_RW(rpm_lvl); +static DEVICE_ATTR_RO(rpm_target_dev_state); +static DEVICE_ATTR_RO(rpm_target_link_state); +static DEVICE_ATTR_RW(spm_lvl); +static DEVICE_ATTR_RO(spm_target_dev_state); +static DEVICE_ATTR_RO(spm_target_link_state); +static DEVICE_ATTR_RW(auto_hibern8); + +static struct attribute *ufs_sysfs_ufshcd_attrs[] = { + &dev_attr_rpm_lvl.attr, + &dev_attr_rpm_target_dev_state.attr, + &dev_attr_rpm_target_link_state.attr, + &dev_attr_spm_lvl.attr, + &dev_attr_spm_target_dev_state.attr, + &dev_attr_spm_target_link_state.attr, + &dev_attr_auto_hibern8.attr, + NULL +}; + +static const struct attribute_group ufs_sysfs_default_group = { + .attrs = ufs_sysfs_ufshcd_attrs, +}; + +static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, + enum desc_idn desc_id, + u8 desc_index, + u8 param_offset, + u8 *sysfs_buf, + u8 param_size) +{ + u8 desc_buf[8] = {0}; + int ret; + + if (param_size > 8) + return -EINVAL; + + ret = ufshcd_read_desc_param(hba, desc_id, desc_index, + param_offset, desc_buf, param_size); + if (ret) + return -EINVAL; + switch (param_size) { + case 1: + ret = sprintf(sysfs_buf, "0x%02X\n", *desc_buf); + break; + case 2: + ret = sprintf(sysfs_buf, "0x%04X\n", + get_unaligned_be16(desc_buf)); + break; + case 4: + ret = sprintf(sysfs_buf, "0x%08X\n", + get_unaligned_be32(desc_buf)); + break; + case 8: + ret = sprintf(sysfs_buf, "0x%016llX\n", + get_unaligned_be64(desc_buf)); + break; + } + + return ret; +} + +#define UFS_DESC_PARAM(_name, _puname, _duname, _size) \ +static ssize_t _name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ufs_hba *hba = dev_get_drvdata(dev); \ + return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ + 0, _duname##_DESC_PARAM##_puname, buf, _size); \ +} \ +static DEVICE_ATTR_RO(_name) + +#define UFS_DEVICE_DESC_PARAM(_name, _uname, _size) \ + UFS_DESC_PARAM(_name, _uname, DEVICE, _size) + +UFS_DEVICE_DESC_PARAM(device_type, _DEVICE_TYPE, 1); +UFS_DEVICE_DESC_PARAM(device_class, _DEVICE_CLASS, 1); +UFS_DEVICE_DESC_PARAM(device_sub_class, _DEVICE_SUB_CLASS, 1); +UFS_DEVICE_DESC_PARAM(protocol, _PRTCL, 1); +UFS_DEVICE_DESC_PARAM(number_of_luns, _NUM_LU, 1); +UFS_DEVICE_DESC_PARAM(number_of_wluns, _NUM_WLU, 1); +UFS_DEVICE_DESC_PARAM(boot_enable, _BOOT_ENBL, 1); +UFS_DEVICE_DESC_PARAM(descriptor_access_enable, _DESC_ACCSS_ENBL, 1); +UFS_DEVICE_DESC_PARAM(initial_power_mode, _INIT_PWR_MODE, 1); +UFS_DEVICE_DESC_PARAM(high_priority_lun, _HIGH_PR_LUN, 1); +UFS_DEVICE_DESC_PARAM(secure_removal_type, _SEC_RMV_TYPE, 1); +UFS_DEVICE_DESC_PARAM(support_security_lun, _SEC_LU, 1); +UFS_DEVICE_DESC_PARAM(bkops_termination_latency, _BKOP_TERM_LT, 1); +UFS_DEVICE_DESC_PARAM(initial_active_icc_level, _ACTVE_ICC_LVL, 1); +UFS_DEVICE_DESC_PARAM(specification_version, _SPEC_VER, 2); +UFS_DEVICE_DESC_PARAM(manufacturing_date, _MANF_DATE, 2); +UFS_DEVICE_DESC_PARAM(manufacturer_id, _MANF_ID, 2); +UFS_DEVICE_DESC_PARAM(rtt_capability, _RTT_CAP, 1); +UFS_DEVICE_DESC_PARAM(rtc_update, _FRQ_RTC, 2); +UFS_DEVICE_DESC_PARAM(ufs_features, _UFS_FEAT, 1); +UFS_DEVICE_DESC_PARAM(ffu_timeout, _FFU_TMT, 1); +UFS_DEVICE_DESC_PARAM(queue_depth, _Q_DPTH, 1); +UFS_DEVICE_DESC_PARAM(device_version, _DEV_VER, 2); +UFS_DEVICE_DESC_PARAM(number_of_secure_wpa, _NUM_SEC_WPA, 1); +UFS_DEVICE_DESC_PARAM(psa_max_data_size, _PSA_MAX_DATA, 4); +UFS_DEVICE_DESC_PARAM(psa_state_timeout, _PSA_TMT, 1); + +static struct attribute *ufs_sysfs_device_descriptor[] = { + &dev_attr_device_type.attr, + &dev_attr_device_class.attr, + &dev_attr_device_sub_class.attr, + &dev_attr_protocol.attr, + &dev_attr_number_of_luns.attr, + &dev_attr_number_of_wluns.attr, + &dev_attr_boot_enable.attr, + &dev_attr_descriptor_access_enable.attr, + &dev_attr_initial_power_mode.attr, + &dev_attr_high_priority_lun.attr, + &dev_attr_secure_removal_type.attr, + &dev_attr_support_security_lun.attr, + &dev_attr_bkops_termination_latency.attr, + &dev_attr_initial_active_icc_level.attr, + &dev_attr_specification_version.attr, + &dev_attr_manufacturing_date.attr, + &dev_attr_manufacturer_id.attr, + &dev_attr_rtt_capability.attr, + &dev_attr_rtc_update.attr, + &dev_attr_ufs_features.attr, + &dev_attr_ffu_timeout.attr, + &dev_attr_queue_depth.attr, + &dev_attr_device_version.attr, + &dev_attr_number_of_secure_wpa.attr, + &dev_attr_psa_max_data_size.attr, + &dev_attr_psa_state_timeout.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_device_descriptor_group = { + .name = "device_descriptor", + .attrs = ufs_sysfs_device_descriptor, +}; + +#define UFS_INTERCONNECT_DESC_PARAM(_name, _uname, _size) \ + UFS_DESC_PARAM(_name, _uname, INTERCONNECT, _size) + +UFS_INTERCONNECT_DESC_PARAM(unipro_version, _UNIPRO_VER, 2); +UFS_INTERCONNECT_DESC_PARAM(mphy_version, _MPHY_VER, 2); + +static struct attribute *ufs_sysfs_interconnect_descriptor[] = { + &dev_attr_unipro_version.attr, + &dev_attr_mphy_version.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_interconnect_descriptor_group = { + .name = "interconnect_descriptor", + .attrs = ufs_sysfs_interconnect_descriptor, +}; + +#define UFS_GEOMETRY_DESC_PARAM(_name, _uname, _size) \ + UFS_DESC_PARAM(_name, _uname, GEOMETRY, _size) + +UFS_GEOMETRY_DESC_PARAM(raw_device_capacity, _DEV_CAP, 8); +UFS_GEOMETRY_DESC_PARAM(max_number_of_luns, _MAX_NUM_LUN, 1); +UFS_GEOMETRY_DESC_PARAM(segment_size, _SEG_SIZE, 4); +UFS_GEOMETRY_DESC_PARAM(allocation_unit_size, _ALLOC_UNIT_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(min_addressable_block_size, _MIN_BLK_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(optimal_read_block_size, _OPT_RD_BLK_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(optimal_write_block_size, _OPT_WR_BLK_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(max_in_buffer_size, _MAX_IN_BUF_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(max_out_buffer_size, _MAX_OUT_BUF_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(rpmb_rw_size, _RPMB_RW_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(dyn_capacity_resource_policy, _DYN_CAP_RSRC_PLC, 1); +UFS_GEOMETRY_DESC_PARAM(data_ordering, _DATA_ORDER, 1); +UFS_GEOMETRY_DESC_PARAM(max_number_of_contexts, _MAX_NUM_CTX, 1); +UFS_GEOMETRY_DESC_PARAM(sys_data_tag_unit_size, _TAG_UNIT_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(sys_data_tag_resource_size, _TAG_RSRC_SIZE, 1); +UFS_GEOMETRY_DESC_PARAM(secure_removal_types, _SEC_RM_TYPES, 1); +UFS_GEOMETRY_DESC_PARAM(memory_types, _MEM_TYPES, 2); +UFS_GEOMETRY_DESC_PARAM(sys_code_memory_max_alloc_units, + _SCM_MAX_NUM_UNITS, 4); +UFS_GEOMETRY_DESC_PARAM(sys_code_memory_capacity_adjustment_factor, + _SCM_CAP_ADJ_FCTR, 2); +UFS_GEOMETRY_DESC_PARAM(non_persist_memory_max_alloc_units, + _NPM_MAX_NUM_UNITS, 4); +UFS_GEOMETRY_DESC_PARAM(non_persist_memory_capacity_adjustment_factor, + _NPM_CAP_ADJ_FCTR, 2); +UFS_GEOMETRY_DESC_PARAM(enh1_memory_max_alloc_units, + _ENM1_MAX_NUM_UNITS, 4); +UFS_GEOMETRY_DESC_PARAM(enh1_memory_capacity_adjustment_factor, + _ENM1_CAP_ADJ_FCTR, 2); +UFS_GEOMETRY_DESC_PARAM(enh2_memory_max_alloc_units, + _ENM2_MAX_NUM_UNITS, 4); +UFS_GEOMETRY_DESC_PARAM(enh2_memory_capacity_adjustment_factor, + _ENM2_CAP_ADJ_FCTR, 2); +UFS_GEOMETRY_DESC_PARAM(enh3_memory_max_alloc_units, + _ENM3_MAX_NUM_UNITS, 4); +UFS_GEOMETRY_DESC_PARAM(enh3_memory_capacity_adjustment_factor, + _ENM3_CAP_ADJ_FCTR, 2); +UFS_GEOMETRY_DESC_PARAM(enh4_memory_max_alloc_units, + _ENM4_MAX_NUM_UNITS, 4); +UFS_GEOMETRY_DESC_PARAM(enh4_memory_capacity_adjustment_factor, + _ENM4_CAP_ADJ_FCTR, 2); + +static struct attribute *ufs_sysfs_geometry_descriptor[] = { + &dev_attr_raw_device_capacity.attr, + &dev_attr_max_number_of_luns.attr, + &dev_attr_segment_size.attr, + &dev_attr_allocation_unit_size.attr, + &dev_attr_min_addressable_block_size.attr, + &dev_attr_optimal_read_block_size.attr, + &dev_attr_optimal_write_block_size.attr, + &dev_attr_max_in_buffer_size.attr, + &dev_attr_max_out_buffer_size.attr, + &dev_attr_rpmb_rw_size.attr, + &dev_attr_dyn_capacity_resource_policy.attr, + &dev_attr_data_ordering.attr, + &dev_attr_max_number_of_contexts.attr, + &dev_attr_sys_data_tag_unit_size.attr, + &dev_attr_sys_data_tag_resource_size.attr, + &dev_attr_secure_removal_types.attr, + &dev_attr_memory_types.attr, + &dev_attr_sys_code_memory_max_alloc_units.attr, + &dev_attr_sys_code_memory_capacity_adjustment_factor.attr, + &dev_attr_non_persist_memory_max_alloc_units.attr, + &dev_attr_non_persist_memory_capacity_adjustment_factor.attr, + &dev_attr_enh1_memory_max_alloc_units.attr, + &dev_attr_enh1_memory_capacity_adjustment_factor.attr, + &dev_attr_enh2_memory_max_alloc_units.attr, + &dev_attr_enh2_memory_capacity_adjustment_factor.attr, + &dev_attr_enh3_memory_max_alloc_units.attr, + &dev_attr_enh3_memory_capacity_adjustment_factor.attr, + &dev_attr_enh4_memory_max_alloc_units.attr, + &dev_attr_enh4_memory_capacity_adjustment_factor.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_geometry_descriptor_group = { + .name = "geometry_descriptor", + .attrs = ufs_sysfs_geometry_descriptor, +}; + +#define UFS_HEALTH_DESC_PARAM(_name, _uname, _size) \ + UFS_DESC_PARAM(_name, _uname, HEALTH, _size) + +UFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1); +UFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1); +UFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1); + +static struct attribute *ufs_sysfs_health_descriptor[] = { + &dev_attr_eol_info.attr, + &dev_attr_life_time_estimation_a.attr, + &dev_attr_life_time_estimation_b.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_health_descriptor_group = { + .name = "health_descriptor", + .attrs = ufs_sysfs_health_descriptor, +}; + +#define UFS_POWER_DESC_PARAM(_name, _uname, _index) \ +static ssize_t _name##_index##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ufs_hba *hba = dev_get_drvdata(dev); \ + return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_POWER, 0, \ + PWR_DESC##_uname##_0 + _index * 2, buf, 2); \ +} \ +static DEVICE_ATTR_RO(_name##_index) + +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 0); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 1); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 2); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 3); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 4); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 5); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 6); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 7); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 8); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 9); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 10); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 11); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 12); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 13); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 14); +UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 15); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 0); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 1); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 2); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 3); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 4); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 5); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 6); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 7); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 8); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 9); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 10); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 11); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 12); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 13); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 14); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 15); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 0); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 1); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 2); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 3); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 4); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 5); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 6); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 7); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 8); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 9); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 10); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 11); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 12); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 13); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 14); +UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 15); + +static struct attribute *ufs_sysfs_power_descriptor[] = { + &dev_attr_active_icc_levels_vcc0.attr, + &dev_attr_active_icc_levels_vcc1.attr, + &dev_attr_active_icc_levels_vcc2.attr, + &dev_attr_active_icc_levels_vcc3.attr, + &dev_attr_active_icc_levels_vcc4.attr, + &dev_attr_active_icc_levels_vcc5.attr, + &dev_attr_active_icc_levels_vcc6.attr, + &dev_attr_active_icc_levels_vcc7.attr, + &dev_attr_active_icc_levels_vcc8.attr, + &dev_attr_active_icc_levels_vcc9.attr, + &dev_attr_active_icc_levels_vcc10.attr, + &dev_attr_active_icc_levels_vcc11.attr, + &dev_attr_active_icc_levels_vcc12.attr, + &dev_attr_active_icc_levels_vcc13.attr, + &dev_attr_active_icc_levels_vcc14.attr, + &dev_attr_active_icc_levels_vcc15.attr, + &dev_attr_active_icc_levels_vccq0.attr, + &dev_attr_active_icc_levels_vccq1.attr, + &dev_attr_active_icc_levels_vccq2.attr, + &dev_attr_active_icc_levels_vccq3.attr, + &dev_attr_active_icc_levels_vccq4.attr, + &dev_attr_active_icc_levels_vccq5.attr, + &dev_attr_active_icc_levels_vccq6.attr, + &dev_attr_active_icc_levels_vccq7.attr, + &dev_attr_active_icc_levels_vccq8.attr, + &dev_attr_active_icc_levels_vccq9.attr, + &dev_attr_active_icc_levels_vccq10.attr, + &dev_attr_active_icc_levels_vccq11.attr, + &dev_attr_active_icc_levels_vccq12.attr, + &dev_attr_active_icc_levels_vccq13.attr, + &dev_attr_active_icc_levels_vccq14.attr, + &dev_attr_active_icc_levels_vccq15.attr, + &dev_attr_active_icc_levels_vccq20.attr, + &dev_attr_active_icc_levels_vccq21.attr, + &dev_attr_active_icc_levels_vccq22.attr, + &dev_attr_active_icc_levels_vccq23.attr, + &dev_attr_active_icc_levels_vccq24.attr, + &dev_attr_active_icc_levels_vccq25.attr, + &dev_attr_active_icc_levels_vccq26.attr, + &dev_attr_active_icc_levels_vccq27.attr, + &dev_attr_active_icc_levels_vccq28.attr, + &dev_attr_active_icc_levels_vccq29.attr, + &dev_attr_active_icc_levels_vccq210.attr, + &dev_attr_active_icc_levels_vccq211.attr, + &dev_attr_active_icc_levels_vccq212.attr, + &dev_attr_active_icc_levels_vccq213.attr, + &dev_attr_active_icc_levels_vccq214.attr, + &dev_attr_active_icc_levels_vccq215.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_power_descriptor_group = { + .name = "power_descriptor", + .attrs = ufs_sysfs_power_descriptor, +}; + +#define UFS_STRING_DESCRIPTOR(_name, _pname) \ +static ssize_t _name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + u8 index; \ + struct ufs_hba *hba = dev_get_drvdata(dev); \ + int ret; \ + int desc_len = QUERY_DESC_MAX_SIZE; \ + u8 *desc_buf; \ + desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_ATOMIC); \ + if (!desc_buf) \ + return -ENOMEM; \ + ret = ufshcd_query_descriptor_retry(hba, \ + UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \ + 0, 0, desc_buf, &desc_len); \ + if (ret) { \ + ret = -EINVAL; \ + goto out; \ + } \ + index = desc_buf[DEVICE_DESC_PARAM##_pname]; \ + memset(desc_buf, 0, QUERY_DESC_MAX_SIZE); \ + if (ufshcd_read_string_desc(hba, index, desc_buf, \ + QUERY_DESC_MAX_SIZE, true)) { \ + ret = -EINVAL; \ + goto out; \ + } \ + ret = snprintf(buf, PAGE_SIZE, "%s\n", \ + desc_buf + QUERY_DESC_HDR_SIZE); \ +out: \ + kfree(desc_buf); \ + return ret; \ +} \ +static DEVICE_ATTR_RO(_name) + +UFS_STRING_DESCRIPTOR(manufacturer_name, _MANF_NAME); +UFS_STRING_DESCRIPTOR(product_name, _PRDCT_NAME); +UFS_STRING_DESCRIPTOR(oem_id, _OEM_ID); +UFS_STRING_DESCRIPTOR(serial_number, _SN); +UFS_STRING_DESCRIPTOR(product_revision, _PRDCT_REV); + +static struct attribute *ufs_sysfs_string_descriptors[] = { + &dev_attr_manufacturer_name.attr, + &dev_attr_product_name.attr, + &dev_attr_oem_id.attr, + &dev_attr_serial_number.attr, + &dev_attr_product_revision.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_string_descriptors_group = { + .name = "string_descriptors", + .attrs = ufs_sysfs_string_descriptors, +}; + +#define UFS_FLAG(_name, _uname) \ +static ssize_t _name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + bool flag; \ + struct ufs_hba *hba = dev_get_drvdata(dev); \ + if (ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \ + QUERY_FLAG_IDN##_uname, &flag)) \ + return -EINVAL; \ + return sprintf(buf, "%s\n", flag ? "true" : "false"); \ +} \ +static DEVICE_ATTR_RO(_name) + +UFS_FLAG(device_init, _FDEVICEINIT); +UFS_FLAG(permanent_wpe, _PERMANENT_WPE); +UFS_FLAG(power_on_wpe, _PWR_ON_WPE); +UFS_FLAG(bkops_enable, _BKOPS_EN); +UFS_FLAG(life_span_mode_enable, _LIFE_SPAN_MODE_ENABLE); +UFS_FLAG(phy_resource_removal, _FPHYRESOURCEREMOVAL); +UFS_FLAG(busy_rtc, _BUSY_RTC); +UFS_FLAG(disable_fw_update, _PERMANENTLY_DISABLE_FW_UPDATE); + +static struct attribute *ufs_sysfs_device_flags[] = { + &dev_attr_device_init.attr, + &dev_attr_permanent_wpe.attr, + &dev_attr_power_on_wpe.attr, + &dev_attr_bkops_enable.attr, + &dev_attr_life_span_mode_enable.attr, + &dev_attr_phy_resource_removal.attr, + &dev_attr_busy_rtc.attr, + &dev_attr_disable_fw_update.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_flags_group = { + .name = "flags", + .attrs = ufs_sysfs_device_flags, +}; + +#define UFS_ATTRIBUTE(_name, _uname) \ +static ssize_t _name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct ufs_hba *hba = dev_get_drvdata(dev); \ + u32 value; \ + if (ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, \ + QUERY_ATTR_IDN##_uname, 0, 0, &value)) \ + return -EINVAL; \ + return sprintf(buf, "0x%08X\n", value); \ +} \ +static DEVICE_ATTR_RO(_name) + +UFS_ATTRIBUTE(boot_lun_enabled, _BOOT_LU_EN); +UFS_ATTRIBUTE(current_power_mode, _POWER_MODE); +UFS_ATTRIBUTE(active_icc_level, _ACTIVE_ICC_LVL); +UFS_ATTRIBUTE(ooo_data_enabled, _OOO_DATA_EN); +UFS_ATTRIBUTE(bkops_status, _BKOPS_STATUS); +UFS_ATTRIBUTE(purge_status, _PURGE_STATUS); +UFS_ATTRIBUTE(max_data_in_size, _MAX_DATA_IN); +UFS_ATTRIBUTE(max_data_out_size, _MAX_DATA_OUT); +UFS_ATTRIBUTE(reference_clock_frequency, _REF_CLK_FREQ); +UFS_ATTRIBUTE(configuration_descriptor_lock, _CONF_DESC_LOCK); +UFS_ATTRIBUTE(max_number_of_rtt, _MAX_NUM_OF_RTT); +UFS_ATTRIBUTE(exception_event_control, _EE_CONTROL); +UFS_ATTRIBUTE(exception_event_status, _EE_STATUS); +UFS_ATTRIBUTE(ffu_status, _FFU_STATUS); +UFS_ATTRIBUTE(psa_state, _PSA_STATE); +UFS_ATTRIBUTE(psa_data_size, _PSA_DATA_SIZE); + +static struct attribute *ufs_sysfs_attributes[] = { + &dev_attr_boot_lun_enabled.attr, + &dev_attr_current_power_mode.attr, + &dev_attr_active_icc_level.attr, + &dev_attr_ooo_data_enabled.attr, + &dev_attr_bkops_status.attr, + &dev_attr_purge_status.attr, + &dev_attr_max_data_in_size.attr, + &dev_attr_max_data_out_size.attr, + &dev_attr_reference_clock_frequency.attr, + &dev_attr_configuration_descriptor_lock.attr, + &dev_attr_max_number_of_rtt.attr, + &dev_attr_exception_event_control.attr, + &dev_attr_exception_event_status.attr, + &dev_attr_ffu_status.attr, + &dev_attr_psa_state.attr, + &dev_attr_psa_data_size.attr, + NULL, +}; + +static const struct attribute_group ufs_sysfs_attributes_group = { + .name = "attributes", + .attrs = ufs_sysfs_attributes, +}; + +static const struct attribute_group *ufs_sysfs_groups[] = { + &ufs_sysfs_default_group, + &ufs_sysfs_device_descriptor_group, + &ufs_sysfs_interconnect_descriptor_group, + &ufs_sysfs_geometry_descriptor_group, + &ufs_sysfs_health_descriptor_group, + &ufs_sysfs_power_descriptor_group, + &ufs_sysfs_string_descriptors_group, + &ufs_sysfs_flags_group, + &ufs_sysfs_attributes_group, + NULL, +}; + +#define UFS_LUN_DESC_PARAM(_pname, _puname, _duname, _size) \ +static ssize_t _pname##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct scsi_device *sdev = to_scsi_device(dev); \ + struct ufs_hba *hba = shost_priv(sdev->host); \ + u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); \ + if (!ufs_is_valid_unit_desc_lun(lun)) \ + return -EINVAL; \ + return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ + lun, _duname##_DESC_PARAM##_puname, buf, _size); \ +} \ +static DEVICE_ATTR_RO(_pname) + +#define UFS_UNIT_DESC_PARAM(_name, _uname, _size) \ + UFS_LUN_DESC_PARAM(_name, _uname, UNIT, _size) + +UFS_UNIT_DESC_PARAM(boot_lun_id, _BOOT_LUN_ID, 1); +UFS_UNIT_DESC_PARAM(lun_write_protect, _LU_WR_PROTECT, 1); +UFS_UNIT_DESC_PARAM(lun_queue_depth, _LU_Q_DEPTH, 1); +UFS_UNIT_DESC_PARAM(psa_sensitive, _PSA_SENSITIVE, 1); +UFS_UNIT_DESC_PARAM(lun_memory_type, _MEM_TYPE, 1); +UFS_UNIT_DESC_PARAM(data_reliability, _DATA_RELIABILITY, 1); +UFS_UNIT_DESC_PARAM(logical_block_size, _LOGICAL_BLK_SIZE, 1); +UFS_UNIT_DESC_PARAM(logical_block_count, _LOGICAL_BLK_COUNT, 8); +UFS_UNIT_DESC_PARAM(erase_block_size, _ERASE_BLK_SIZE, 4); +UFS_UNIT_DESC_PARAM(provisioning_type, _PROVISIONING_TYPE, 1); +UFS_UNIT_DESC_PARAM(physical_memory_resourse_count, _PHY_MEM_RSRC_CNT, 8); +UFS_UNIT_DESC_PARAM(context_capabilities, _CTX_CAPABILITIES, 2); +UFS_UNIT_DESC_PARAM(large_unit_granularity, _LARGE_UNIT_SIZE_M1, 1); + +static struct attribute *ufs_sysfs_unit_descriptor[] = { + &dev_attr_boot_lun_id.attr, + &dev_attr_lun_write_protect.attr, + &dev_attr_lun_queue_depth.attr, + &dev_attr_psa_sensitive.attr, + &dev_attr_lun_memory_type.attr, + &dev_attr_data_reliability.attr, + &dev_attr_logical_block_size.attr, + &dev_attr_logical_block_count.attr, + &dev_attr_erase_block_size.attr, + &dev_attr_provisioning_type.attr, + &dev_attr_physical_memory_resourse_count.attr, + &dev_attr_context_capabilities.attr, + &dev_attr_large_unit_granularity.attr, + NULL, +}; + +const struct attribute_group ufs_sysfs_unit_descriptor_group = { + .name = "unit_descriptor", + .attrs = ufs_sysfs_unit_descriptor, +}; + +static ssize_t dyn_cap_needed_attribute_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value; + struct scsi_device *sdev = to_scsi_device(dev); + struct ufs_hba *hba = shost_priv(sdev->host); + u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); + + if (ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value)) + return -EINVAL; + return sprintf(buf, "0x%08X\n", value); +} +static DEVICE_ATTR_RO(dyn_cap_needed_attribute); + +static struct attribute *ufs_sysfs_lun_attributes[] = { + &dev_attr_dyn_cap_needed_attribute.attr, + NULL, +}; + +const struct attribute_group ufs_sysfs_lun_attributes_group = { + .attrs = ufs_sysfs_lun_attributes, +}; + +void ufs_sysfs_add_nodes(struct device *dev) +{ + int ret; + + ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups); + if (ret) + dev_err(dev, + "%s: sysfs groups creation failed (err = %d)\n", + __func__, ret); +} + +void ufs_sysfs_remove_nodes(struct device *dev) +{ + sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups); +} diff --git a/drivers/scsi/ufs/ufs-sysfs.h b/drivers/scsi/ufs/ufs-sysfs.h new file mode 100644 index 000000000000..e5621e59a432 --- /dev/null +++ b/drivers/scsi/ufs/ufs-sysfs.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (C) 2018 Western Digital Corporation + */ + +#ifndef __UFS_SYSFS_H__ +#define __UFS_SYSFS_H__ + +#include <linux/sysfs.h> + +#include "ufshcd.h" + +void ufs_sysfs_add_nodes(struct device *dev); +void ufs_sysfs_remove_nodes(struct device *dev); + +extern const struct attribute_group ufs_sysfs_unit_descriptor_group; +extern const struct attribute_group ufs_sysfs_lun_attributes_group; +#endif diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 54deeb754db5..14e5bf7af0bb 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -130,17 +130,44 @@ enum { /* Flag idn for Query Requests*/ enum flag_idn { - QUERY_FLAG_IDN_FDEVICEINIT = 0x01, - QUERY_FLAG_IDN_PWR_ON_WPE = 0x03, - QUERY_FLAG_IDN_BKOPS_EN = 0x04, + QUERY_FLAG_IDN_FDEVICEINIT = 0x01, + QUERY_FLAG_IDN_PERMANENT_WPE = 0x02, + QUERY_FLAG_IDN_PWR_ON_WPE = 0x03, + QUERY_FLAG_IDN_BKOPS_EN = 0x04, + QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE = 0x05, + QUERY_FLAG_IDN_PURGE_ENABLE = 0x06, + QUERY_FLAG_IDN_RESERVED2 = 0x07, + QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08, + QUERY_FLAG_IDN_BUSY_RTC = 0x09, + QUERY_FLAG_IDN_RESERVED3 = 0x0A, + QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE = 0x0B, }; /* Attribute idn for Query requests */ enum attr_idn { - QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03, - QUERY_ATTR_IDN_BKOPS_STATUS = 0x05, - QUERY_ATTR_IDN_EE_CONTROL = 0x0D, - QUERY_ATTR_IDN_EE_STATUS = 0x0E, + QUERY_ATTR_IDN_BOOT_LU_EN = 0x00, + QUERY_ATTR_IDN_RESERVED = 0x01, + QUERY_ATTR_IDN_POWER_MODE = 0x02, + QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03, + QUERY_ATTR_IDN_OOO_DATA_EN = 0x04, + QUERY_ATTR_IDN_BKOPS_STATUS = 0x05, + QUERY_ATTR_IDN_PURGE_STATUS = 0x06, + QUERY_ATTR_IDN_MAX_DATA_IN = 0x07, + QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08, + QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09, + QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A, + QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B, + QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C, + QUERY_ATTR_IDN_EE_CONTROL = 0x0D, + QUERY_ATTR_IDN_EE_STATUS = 0x0E, + QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F, + QUERY_ATTR_IDN_CNTX_CONF = 0x10, + QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11, + QUERY_ATTR_IDN_RESERVED2 = 0x12, + QUERY_ATTR_IDN_RESERVED3 = 0x13, + QUERY_ATTR_IDN_FFU_STATUS = 0x14, + QUERY_ATTR_IDN_PSA_STATE = 0x15, + QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16, }; /* Descriptor idn for Query requests */ @@ -154,6 +181,7 @@ enum desc_idn { QUERY_DESC_IDN_RFU_1 = 0x6, QUERY_DESC_IDN_GEOMETRY = 0x7, QUERY_DESC_IDN_POWER = 0x8, + QUERY_DESC_IDN_HEALTH = 0x9, QUERY_DESC_IDN_MAX, }; @@ -169,6 +197,7 @@ enum ufs_desc_def_size { QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, QUERY_DESC_POWER_DEF_SIZE = 0x62, + QUERY_DESC_HEALTH_DEF_SIZE = 0x25, }; /* Unit descriptor parameters offsets in bytes*/ @@ -180,6 +209,7 @@ enum unit_desc_param { UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4, UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5, UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6, + UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7, UNIT_DESC_PARAM_MEM_TYPE = 0x8, UNIT_DESC_PARAM_DATA_RELIABILITY = 0x9, UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA, @@ -220,6 +250,67 @@ enum device_desc_param { DEVICE_DESC_PARAM_UD_LEN = 0x1B, DEVICE_DESC_PARAM_RTT_CAP = 0x1C, DEVICE_DESC_PARAM_FRQ_RTC = 0x1D, + DEVICE_DESC_PARAM_UFS_FEAT = 0x1F, + DEVICE_DESC_PARAM_FFU_TMT = 0x20, + DEVICE_DESC_PARAM_Q_DPTH = 0x21, + DEVICE_DESC_PARAM_DEV_VER = 0x22, + DEVICE_DESC_PARAM_NUM_SEC_WPA = 0x24, + DEVICE_DESC_PARAM_PSA_MAX_DATA = 0x25, + DEVICE_DESC_PARAM_PSA_TMT = 0x29, + DEVICE_DESC_PARAM_PRDCT_REV = 0x2A, +}; + +/* Interconnect descriptor parameters offsets in bytes*/ +enum interconnect_desc_param { + INTERCONNECT_DESC_PARAM_LEN = 0x0, + INTERCONNECT_DESC_PARAM_TYPE = 0x1, + INTERCONNECT_DESC_PARAM_UNIPRO_VER = 0x2, + INTERCONNECT_DESC_PARAM_MPHY_VER = 0x4, +}; + +/* Geometry descriptor parameters offsets in bytes*/ +enum geometry_desc_param { + GEOMETRY_DESC_PARAM_LEN = 0x0, + GEOMETRY_DESC_PARAM_TYPE = 0x1, + GEOMETRY_DESC_PARAM_DEV_CAP = 0x4, + GEOMETRY_DESC_PARAM_MAX_NUM_LUN = 0xC, + GEOMETRY_DESC_PARAM_SEG_SIZE = 0xD, + GEOMETRY_DESC_PARAM_ALLOC_UNIT_SIZE = 0x11, + GEOMETRY_DESC_PARAM_MIN_BLK_SIZE = 0x12, + GEOMETRY_DESC_PARAM_OPT_RD_BLK_SIZE = 0x13, + GEOMETRY_DESC_PARAM_OPT_WR_BLK_SIZE = 0x14, + GEOMETRY_DESC_PARAM_MAX_IN_BUF_SIZE = 0x15, + GEOMETRY_DESC_PARAM_MAX_OUT_BUF_SIZE = 0x16, + GEOMETRY_DESC_PARAM_RPMB_RW_SIZE = 0x17, + GEOMETRY_DESC_PARAM_DYN_CAP_RSRC_PLC = 0x18, + GEOMETRY_DESC_PARAM_DATA_ORDER = 0x19, + GEOMETRY_DESC_PARAM_MAX_NUM_CTX = 0x1A, + GEOMETRY_DESC_PARAM_TAG_UNIT_SIZE = 0x1B, + GEOMETRY_DESC_PARAM_TAG_RSRC_SIZE = 0x1C, + GEOMETRY_DESC_PARAM_SEC_RM_TYPES = 0x1D, + GEOMETRY_DESC_PARAM_MEM_TYPES = 0x1E, + GEOMETRY_DESC_PARAM_SCM_MAX_NUM_UNITS = 0x20, + GEOMETRY_DESC_PARAM_SCM_CAP_ADJ_FCTR = 0x24, + GEOMETRY_DESC_PARAM_NPM_MAX_NUM_UNITS = 0x26, + GEOMETRY_DESC_PARAM_NPM_CAP_ADJ_FCTR = 0x2A, + GEOMETRY_DESC_PARAM_ENM1_MAX_NUM_UNITS = 0x2C, + GEOMETRY_DESC_PARAM_ENM1_CAP_ADJ_FCTR = 0x30, + GEOMETRY_DESC_PARAM_ENM2_MAX_NUM_UNITS = 0x32, + GEOMETRY_DESC_PARAM_ENM2_CAP_ADJ_FCTR = 0x36, + GEOMETRY_DESC_PARAM_ENM3_MAX_NUM_UNITS = 0x38, + GEOMETRY_DESC_PARAM_ENM3_CAP_ADJ_FCTR = 0x3C, + GEOMETRY_DESC_PARAM_ENM4_MAX_NUM_UNITS = 0x3E, + GEOMETRY_DESC_PARAM_ENM4_CAP_ADJ_FCTR = 0x42, + GEOMETRY_DESC_PARAM_OPT_LOG_BLK_SIZE = 0x44, +}; + +/* Health descriptor parameters offsets in bytes*/ +enum health_desc_param { + HEALTH_DESC_PARAM_LEN = 0x0, + HEALTH_DESC_PARAM_TYPE = 0x1, + HEALTH_DESC_PARAM_EOL_INFO = 0x2, + HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3, + HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4, }; /* @@ -529,4 +620,14 @@ struct ufs_dev_desc { char model[MAX_MODEL_LEN + 1]; }; +/** + * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor + * @lun: LU number to check + * @return: true if the lun has a matching unit descriptor, false otherwise + */ +static inline bool ufs_is_valid_unit_desc_lun(u8 lun) +{ + return lun == UFS_UPIU_RPMB_WLUN || (lun < UFS_UPIU_MAX_GENERAL_LUN); +} + #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index 925b0ec7ec54..ffe6f82182ba 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -75,8 +75,7 @@ static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = { #ifdef CONFIG_PM_SLEEP /** * ufshcd_pci_suspend - suspend power management function - * @pdev: pointer to PCI device handle - * @state: power state + * @dev: pointer to PCI device handle * * Returns 0 if successful * Returns non-zero otherwise @@ -88,7 +87,7 @@ static int ufshcd_pci_suspend(struct device *dev) /** * ufshcd_pci_resume - resume power management function - * @pdev: pointer to PCI device handle + * @dev: pointer to PCI device handle * * Returns 0 if successful * Returns non-zero otherwise @@ -126,7 +125,7 @@ static void ufshcd_pci_shutdown(struct pci_dev *pdev) /** * ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space * data structure memory - * @pdev - pointer to PCI handle + * @pdev: pointer to PCI handle */ static void ufshcd_pci_remove(struct pci_dev *pdev) { diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c7da2c185990..c5b1bf1cadcb 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -41,9 +41,11 @@ #include <linux/devfreq.h> #include <linux/nls.h> #include <linux/of.h> +#include <linux/bitfield.h> #include "ufshcd.h" #include "ufs_quirks.h" #include "unipro.h" +#include "ufs-sysfs.h" #define CREATE_TRACE_POINTS #include <trace/events/ufs.h> @@ -150,7 +152,7 @@ enum { #define ufshcd_is_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) -static struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { +struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE}, {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE}, @@ -523,7 +525,7 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, /** * ufshcd_get_intr_mask - Get the interrupt bit mask - * @hba - Pointer to adapter instance + * @hba: Pointer to adapter instance * * Returns interrupt bit mask per version */ @@ -550,7 +552,7 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) /** * ufshcd_get_ufs_version - Get the UFS version supported by the HBA - * @hba - Pointer to adapter instance + * @hba: Pointer to adapter instance * * Returns UFSHCI version supported by the controller */ @@ -577,7 +579,7 @@ static inline bool ufshcd_is_device_present(struct ufs_hba *hba) /** * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status - * @lrb: pointer to local command reference block + * @lrbp: pointer to local command reference block * * This function is used to get the OCS field from UTRD * Returns the OCS field in the UTRD @@ -813,28 +815,6 @@ static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) ? false : true; } -static const char *ufschd_uic_link_state_to_string( - enum uic_link_state state) -{ - switch (state) { - case UIC_LINK_OFF_STATE: return "OFF"; - case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; - case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; - default: return "UNKNOWN"; - } -} - -static const char *ufschd_ufs_dev_pwr_mode_to_string( - enum ufs_dev_pwr_mode state) -{ - switch (state) { - case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; - case UFS_SLEEP_PWR_MODE: return "SLEEP"; - case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; - default: return "UNKNOWN"; - } -} - u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) { /* HCI version 1.0 and 1.1 supports UniPro 1.41 */ @@ -1759,7 +1739,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) /** * ufshcd_copy_sense_data - Copy sense data in case of check condition - * @lrb - pointer to local reference block + * @lrbp: pointer to local reference block */ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) { @@ -1781,7 +1761,7 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) * ufshcd_copy_query_response() - Copy the Query Response and the data * descriptor * @hba: per adapter instance - * @lrb - pointer to local reference block + * @lrbp: pointer to local reference block */ static int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) @@ -1882,7 +1862,7 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) /** * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command * @hba: per adapter instance - * @uic_command: UIC command + * @uic_cmd: UIC command * * Must be called with mutex held. * Returns 0 only if success. @@ -1965,7 +1945,8 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) /** * ufshcd_map_sg - Map scatter-gather list to prdt - * @lrbp - pointer to local reference block + * @hba: per adapter instance + * @lrbp: pointer to local reference block * * Returns 0 in case of success, non-zero value in case of failure */ @@ -2101,8 +2082,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, /** * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc, * for scsi commands - * @lrbp - local reference block pointer - * @upiu_flags - flags + * @lrbp: local reference block pointer + * @upiu_flags: flags */ static void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags) @@ -2190,8 +2171,8 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) /** * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU) * for Device Management Purposes - * @hba - per adapter instance - * @lrb - pointer to local reference block + * @hba: per adapter instance + * @lrbp: pointer to local reference block */ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { @@ -2218,8 +2199,8 @@ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) /** * ufshcd_comp_scsi_upiu - UFS Protocol Information Unit(UPIU) * for SCSI Purposes - * @hba - per adapter instance - * @lrb - pointer to local reference block + * @hba: per adapter instance + * @lrbp: pointer to local reference block */ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { @@ -2243,24 +2224,9 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) return ret; } -/* - * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN - * @scsi_lun: scsi LUN id - * - * Returns UPIU LUN id - */ -static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun) -{ - if (scsi_is_wlun(scsi_lun)) - return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID) - | UFS_UPIU_WLUN_ID; - else - return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID; -} - /** * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID - * @scsi_lun: UPIU W-LUN id + * @upiu_wlun_id: UPIU W-LUN id * * Returns SCSI W-LUN id */ @@ -2271,8 +2237,8 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id) /** * ufshcd_queuecommand - main entry point for SCSI requests + * @host: SCSI host pointer * @cmd: command from SCSI Midlayer - * @done: call back function * * Returns 0 for success, non-zero in case of failure */ @@ -2513,7 +2479,7 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, /** * ufshcd_get_dev_cmd_tag - Get device management command tag * @hba: per-adapter instance - * @tag: pointer to variable with available slot value + * @tag_out: pointer to variable with available slot value * * Get a free slot and lock it until device management command * completes. @@ -2550,9 +2516,9 @@ static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag) /** * ufshcd_exec_dev_cmd - API for sending device management requests - * @hba - UFS hba - * @cmd_type - specifies the type (NOP, Query...) - * @timeout - time in seconds + * @hba: UFS hba + * @cmd_type: specifies the type (NOP, Query...) + * @timeout: time in seconds * * NOTE: Since there is only one available tag for device management commands, * it is expected you hold the hba->dev_cmd.lock mutex. @@ -2649,10 +2615,10 @@ static int ufshcd_query_flag_retry(struct ufs_hba *hba, /** * ufshcd_query_flag() - API function for sending flag query requests - * hba: per-adapter instance - * query_opcode: flag query to perform - * idn: flag idn to access - * flag_res: the flag value after the query request completes + * @hba: per-adapter instance + * @opcode: flag query to perform + * @idn: flag idn to access + * @flag_res: the flag value after the query request completes * * Returns 0 for success, non-zero in case of failure */ @@ -2716,17 +2682,17 @@ out_unlock: /** * ufshcd_query_attr - API function for sending attribute requests - * hba: per-adapter instance - * opcode: attribute opcode - * idn: attribute idn to access - * index: index field - * selector: selector field - * attr_val: the attribute value after the query request completes + * @hba: per-adapter instance + * @opcode: attribute opcode + * @idn: attribute idn to access + * @index: index field + * @selector: selector field + * @attr_val: the attribute value after the query request completes * * Returns 0 for success, non-zero in case of failure */ -static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, - enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) +int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) { struct ufs_query_req *request = NULL; struct ufs_query_res *response = NULL; @@ -2880,25 +2846,24 @@ out: } /** - * ufshcd_query_descriptor_retry - API function for sending descriptor - * requests - * hba: per-adapter instance - * opcode: attribute opcode - * idn: attribute idn to access - * index: index field - * selector: selector field - * desc_buf: the buffer that contains the descriptor - * buf_len: length parameter passed to the device + * ufshcd_query_descriptor_retry - API function for sending descriptor requests + * @hba: per-adapter instance + * @opcode: attribute opcode + * @idn: attribute idn to access + * @index: index field + * @selector: selector field + * @desc_buf: the buffer that contains the descriptor + * @buf_len: length parameter passed to the device * * Returns 0 for success, non-zero in case of failure. * The buf_len parameter will contain, on return, the length parameter * received on the response. */ -static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, - enum query_opcode opcode, - enum desc_idn idn, u8 index, - u8 selector, - u8 *desc_buf, int *buf_len) +int ufshcd_query_descriptor_retry(struct ufs_hba *hba, + enum query_opcode opcode, + enum desc_idn idn, u8 index, + u8 selector, + u8 *desc_buf, int *buf_len) { int err; int retries; @@ -2987,6 +2952,9 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, case QUERY_DESC_IDN_STRING: *desc_len = QUERY_DESC_MAX_SIZE; break; + case QUERY_DESC_IDN_HEALTH: + *desc_len = hba->desc_size.hlth_desc; + break; case QUERY_DESC_IDN_RFU_0: case QUERY_DESC_IDN_RFU_1: *desc_len = 0; @@ -3010,12 +2978,12 @@ EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); * * Return 0 in case of success, non-zero otherwise */ -static int ufshcd_read_desc_param(struct ufs_hba *hba, - enum desc_idn desc_id, - int desc_index, - u8 param_offset, - u8 *param_read_buf, - u8 param_size) +int ufshcd_read_desc_param(struct ufs_hba *hba, + enum desc_idn desc_id, + int desc_index, + u8 param_offset, + u8 *param_read_buf, + u8 param_size) { int ret; u8 *desc_buf; @@ -3110,9 +3078,8 @@ static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) * * Return 0 in case of success, non-zero otherwise */ -#define ASCII_STD true -static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, - u8 *buf, u32 size, bool ascii) +int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, + u8 *buf, u32 size, bool ascii) { int err = 0; @@ -3189,7 +3156,7 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba, * Unit descriptors are only available for general purpose LUs (LUN id * from 0 to 7) and RPMB Well known LU. */ - if (lun != UFS_UPIU_RPMB_WLUN && (lun >= UFS_UPIU_MAX_GENERAL_LUN)) + if (!ufs_is_valid_unit_desc_lun(lun)) return -EOPNOTSUPP; return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun, @@ -3742,6 +3709,18 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) return ret; } +static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) +{ + unsigned long flags; + + if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit) + return; + + spin_lock_irqsave(hba->host->host_lock, flags); + ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); + spin_unlock_irqrestore(hba->host->host_lock, flags); +} + /** * ufshcd_init_pwr_info - setting the POR (power on reset) * values in hba power info @@ -3912,7 +3891,7 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, /** * ufshcd_complete_dev_init() - checks device readiness - * hba: per-adapter instance + * @hba: per-adapter instance * * Set fDeviceInit flag and poll until device toggles it. */ @@ -4453,7 +4432,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8 *resp) /** * ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status - * @lrb: pointer to local reference block of completed command + * @lrbp: pointer to local reference block of completed command * @scsi_status: SCSI command status * * Returns value base on SCSI command status @@ -4488,7 +4467,7 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status) /** * ufshcd_transfer_rsp_status - Get overall status of the response * @hba: per adapter instance - * @lrb: pointer to local reference block of completed command + * @lrbp: pointer to local reference block of completed command * * Returns result of the command to notify SCSI midlayer */ @@ -5796,7 +5775,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) /** * ufshcd_eh_host_reset_handler - host reset handler registered to scsi layer - * @cmd - SCSI command pointer + * @cmd: SCSI command pointer * * Returns SUCCESS/FAILED */ @@ -5981,11 +5960,11 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba) * will take effect only when its sent to "UFS device" well known logical unit * hence we require the scsi_device instance to represent this logical unit in * order for the UFS host driver to send the SSU command for power management. - + * * We also require the scsi_device instance for "RPMB" (Replay Protected Memory * Block) LU so user space process can control this LU. User space may also * want to have access to BOOT LU. - + * * This function adds scsi device instances for each of all well known LUs * (except "REPORT LUNS" LU). * @@ -6054,7 +6033,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba, model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, - QUERY_DESC_MAX_SIZE, ASCII_STD); + QUERY_DESC_MAX_SIZE, true/*ASCII*/); if (err) { dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", __func__, err); @@ -6300,6 +6279,10 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba) &hba->desc_size.geom_desc); if (err) hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, + &hba->desc_size.hlth_desc); + if (err) + hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } static void ufshcd_def_desc_sizes(struct ufs_hba *hba) @@ -6310,6 +6293,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba) hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; + hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } /** @@ -6338,6 +6322,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* UniPro link is active now */ ufshcd_set_link_active(hba); + /* Enable Auto-Hibernate if configured */ + ufshcd_auto_hibern8_enable(hba); + ret = ufshcd_verify_dev_init(hba); if (ret) goto out; @@ -6496,6 +6483,12 @@ static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd) return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER; } +static const struct attribute_group *ufshcd_driver_groups[] = { + &ufs_sysfs_unit_descriptor_group, + &ufs_sysfs_lun_attributes_group, + NULL, +}; + static struct scsi_host_template ufshcd_driver_template = { .module = THIS_MODULE, .name = UFSHCD, @@ -6515,6 +6508,7 @@ static struct scsi_host_template ufshcd_driver_template = { .can_queue = UFSHCD_CAN_QUEUE, .max_host_blocked = 1, .track_queue_depth = 1, + .sdev_groups = ufshcd_driver_groups, }; static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, @@ -7415,6 +7409,10 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) /* Schedule clock gating in case of no access to UFS device yet */ ufshcd_release(hba); + + /* Enable Auto-Hibernate if configured */ + ufshcd_auto_hibern8_enable(hba); + goto out; set_old_link_state: @@ -7436,7 +7434,6 @@ out: /** * ufshcd_system_suspend - system suspend routine * @hba: per adapter instance - * @pm_op: runtime PM or system PM * * Check the description of ufshcd_suspend() function for more details. * @@ -7587,133 +7584,6 @@ int ufshcd_runtime_idle(struct ufs_hba *hba) } EXPORT_SYMBOL(ufshcd_runtime_idle); -static inline ssize_t ufshcd_pm_lvl_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count, - bool rpm) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - unsigned long flags, value; - - if (kstrtoul(buf, 0, &value)) - return -EINVAL; - - if (value >= UFS_PM_LVL_MAX) - return -EINVAL; - - spin_lock_irqsave(hba->host->host_lock, flags); - if (rpm) - hba->rpm_lvl = value; - else - hba->spm_lvl = value; - spin_unlock_irqrestore(hba->host->host_lock, flags); - return count; -} - -static ssize_t ufshcd_rpm_lvl_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - int curr_len; - u8 lvl; - - curr_len = snprintf(buf, PAGE_SIZE, - "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n", - hba->rpm_lvl, - ufschd_ufs_dev_pwr_mode_to_string( - ufs_pm_lvl_states[hba->rpm_lvl].dev_state), - ufschd_uic_link_state_to_string( - ufs_pm_lvl_states[hba->rpm_lvl].link_state)); - - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), - "\nAll available Runtime PM levels info:\n"); - for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), - "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n", - lvl, - ufschd_ufs_dev_pwr_mode_to_string( - ufs_pm_lvl_states[lvl].dev_state), - ufschd_uic_link_state_to_string( - ufs_pm_lvl_states[lvl].link_state)); - - return curr_len; -} - -static ssize_t ufshcd_rpm_lvl_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - return ufshcd_pm_lvl_store(dev, attr, buf, count, true); -} - -static void ufshcd_add_rpm_lvl_sysfs_nodes(struct ufs_hba *hba) -{ - hba->rpm_lvl_attr.show = ufshcd_rpm_lvl_show; - hba->rpm_lvl_attr.store = ufshcd_rpm_lvl_store; - sysfs_attr_init(&hba->rpm_lvl_attr.attr); - hba->rpm_lvl_attr.attr.name = "rpm_lvl"; - hba->rpm_lvl_attr.attr.mode = 0644; - if (device_create_file(hba->dev, &hba->rpm_lvl_attr)) - dev_err(hba->dev, "Failed to create sysfs for rpm_lvl\n"); -} - -static ssize_t ufshcd_spm_lvl_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - int curr_len; - u8 lvl; - - curr_len = snprintf(buf, PAGE_SIZE, - "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n", - hba->spm_lvl, - ufschd_ufs_dev_pwr_mode_to_string( - ufs_pm_lvl_states[hba->spm_lvl].dev_state), - ufschd_uic_link_state_to_string( - ufs_pm_lvl_states[hba->spm_lvl].link_state)); - - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), - "\nAll available System PM levels info:\n"); - for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), - "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n", - lvl, - ufschd_ufs_dev_pwr_mode_to_string( - ufs_pm_lvl_states[lvl].dev_state), - ufschd_uic_link_state_to_string( - ufs_pm_lvl_states[lvl].link_state)); - - return curr_len; -} - -static ssize_t ufshcd_spm_lvl_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - return ufshcd_pm_lvl_store(dev, attr, buf, count, false); -} - -static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba) -{ - hba->spm_lvl_attr.show = ufshcd_spm_lvl_show; - hba->spm_lvl_attr.store = ufshcd_spm_lvl_store; - sysfs_attr_init(&hba->spm_lvl_attr.attr); - hba->spm_lvl_attr.attr.name = "spm_lvl"; - hba->spm_lvl_attr.attr.mode = 0644; - if (device_create_file(hba->dev, &hba->spm_lvl_attr)) - dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n"); -} - -static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba) -{ - ufshcd_add_rpm_lvl_sysfs_nodes(hba); - ufshcd_add_spm_lvl_sysfs_nodes(hba); -} - -static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba) -{ - device_remove_file(hba->dev, &hba->rpm_lvl_attr); - device_remove_file(hba->dev, &hba->spm_lvl_attr); -} - /** * ufshcd_shutdown - shutdown routine * @hba: per adapter instance @@ -7747,11 +7617,11 @@ EXPORT_SYMBOL(ufshcd_shutdown); /** * ufshcd_remove - de-allocate SCSI host and host memory space * data structure memory - * @hba - per adapter instance + * @hba: per adapter instance */ void ufshcd_remove(struct ufs_hba *hba) { - ufshcd_remove_sysfs_nodes(hba); + ufs_sysfs_remove_nodes(hba->dev); scsi_remove_host(hba->host); /* disable interrupts */ ufshcd_disable_intr(hba, hba->intr_mask); @@ -7986,6 +7856,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE); + /* Set the default auto-hiberate idle timer value to 150 ms */ + if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) { + hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) | + FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3); + } + /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); @@ -7998,7 +7874,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_set_ufs_dev_active(hba); async_schedule(ufshcd_async_scan, hba); - ufshcd_add_sysfs_nodes(hba); + ufs_sysfs_add_nodes(hba->dev); return 0; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 1332e544da92..8110dcd04d22 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -229,6 +229,7 @@ struct ufs_desc_size { int interc_desc; int unit_desc; int conf_desc; + int hlth_desc; }; /** @@ -530,6 +531,9 @@ struct ufs_hba { struct device_attribute spm_lvl_attr; int pm_op_in_progress; + /* Auto-Hibernate Idle Timer register value */ + u32 ahit; + struct ufshcd_lrb *lrb; unsigned long lrb_in_use; @@ -841,8 +845,24 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info) } /* Expose Query-Request API */ +int ufshcd_query_descriptor_retry(struct ufs_hba *hba, + enum query_opcode opcode, + enum desc_idn idn, u8 index, + u8 selector, + u8 *desc_buf, int *buf_len); +int ufshcd_read_desc_param(struct ufs_hba *hba, + enum desc_idn desc_id, + int desc_index, + u8 param_offset, + u8 *param_read_buf, + u8 param_size); +int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 selector, u32 *attr_val); int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); +int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, + u8 *buf, u32 size, bool ascii); + int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); @@ -985,4 +1005,21 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) hba->vops->dbg_register_dump(hba); } +extern struct ufs_pm_lvl_states ufs_pm_lvl_states[]; + +/* + * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN + * @scsi_lun: scsi LUN id + * + * Returns UPIU LUN id + */ +static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun) +{ + if (scsi_is_wlun(scsi_lun)) + return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID) + | UFS_UPIU_WLUN_ID; + else + return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID; +} + #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 1a1b5d9fe514..bb5d9c7f3353 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -86,6 +86,7 @@ enum { enum { MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F, MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000, + MASK_AUTO_HIBERN8_SUPPORT = 0x00800000, MASK_64_ADDRESSING_SUPPORT = 0x01000000, MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000, MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000, @@ -119,6 +120,12 @@ enum { #define MANUFACTURE_ID_MASK UFS_MASK(0xFFFF, 0) #define PRODUCT_ID_MASK UFS_MASK(0xFFFF, 16) +/* AHIT - Auto-Hibernate Idle Timer */ +#define UFSHCI_AHIBERN8_TIMER_MASK GENMASK(9, 0) +#define UFSHCI_AHIBERN8_SCALE_MASK GENMASK(12, 10) +#define UFSHCI_AHIBERN8_SCALE_FACTOR 10 +#define UFSHCI_AHIBERN8_MAX (1023 * 100000) + /* * IS - Interrupt Status - 20h */ |