diff options
Diffstat (limited to 'drivers/scsi')
502 files changed, 13412 insertions, 16598 deletions
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 16957d7ac414..0068963bb933 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -*- mode: c; c-basic-offset: 8 -*- */ /* NCR (or Symbios) 53c700 and 53c700-66 Driver @@ -5,19 +6,6 @@ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.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 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 program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- */ diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index e41e51f1da71..c25e8a54e869 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* @@ -5,14 +6,6 @@ Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com> - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation. - - 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 complete details. The author respectfully requests that any modifications to this software be sent directly to him for evaluation and testing. diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 8d47e2c88d24..6182cc8a0344 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -1,17 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com> - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation. - - 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 complete details. The author respectfully requests that any modifications to this software be sent directly to him for evaluation and testing. diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d528018e6fa8..75f66f8ad3ea 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only menu "SCSI device support" config SCSI_MOD @@ -98,28 +99,6 @@ config CHR_DEV_ST To compile this driver as a module, choose M here and read <file:Documentation/scsi/scsi.txt>. The module will be called st. -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives cannot be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage, - you may be able to drive the USB-x0 and DI-x0 drives as well. - Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - <http://www.tldp.org/docs.html#howto> and - <file:Documentation/scsi/osst.txt> in the kernel source. - More info on the OnStream driver may be found on - <http://sourceforge.net/projects/osst/> - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. The module will be called osst. - config BLK_DEV_SR tristate "SCSI CDROM support" depends on SCSI && BLK_DEV @@ -182,7 +161,7 @@ config CHR_DEV_SCH If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt> and + say M here and read <file:Documentation/kbuild/modules.rst> and <file:Documentation/scsi/scsi.txt>. The module will be called ch.o. If unsure, say N. @@ -663,6 +642,41 @@ config SCSI_DMX3191D To compile this driver as a module, choose M here: the module will be called dmx3191d. +config SCSI_FDOMAIN + tristate + depends on SCSI + +config SCSI_FDOMAIN_PCI + tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support" + depends on PCI && SCSI + select SCSI_FDOMAIN + help + This is support for Future Domain's PCI SCSI host adapters (TMC-3260) + and other adapters with PCI bus based on the Future Domain chipsets + (Adaptec AHA-2920A). + + 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_pci. + +config SCSI_FDOMAIN_ISA + tristate "Future Domain 16xx ISA SCSI support" + depends on ISA && SCSI + select CHECK_SIGNATURE + select SCSI_FDOMAIN + help + This is support for Future Domain's 16-bit SCSI host adapters + (TMC-1660/1680, TMC-1650/1670, TMC-1610M/MER/MEX) and other adapters + with ISA bus based on the Future Domain chipsets (Quantum ISA-200S, + ISA-250MG; and at least one IBM board). + + To compile this driver as a module, choose M here: the + module will be called fdomain_isa. + config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" depends on PCI && SCSI @@ -1473,7 +1487,7 @@ config ZFCP This driver is also available as a module. This module will be called zfcp. If you want to compile it as a module, say M here - and read <file:Documentation/kbuild/modules.txt>. + and read <file:Documentation/kbuild/modules.rst>. config SCSI_PMCRAID tristate "PMC SIERRA Linux MaxRAID adapter support" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 8826111fdf4a..aeda53901064 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -76,6 +76,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_FDOMAIN) += fdomain.o +obj-$(CONFIG_SCSI_FDOMAIN_PCI) += fdomain_pci.o +obj-$(CONFIG_SCSI_FDOMAIN_ISA) += fdomain_isa.o obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o @@ -143,7 +146,6 @@ obj-$(CONFIG_SCSI_WD719X) += wd719x.o obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_CHR_DEV_ST) += st.o -obj-$(CONFIG_CHR_DEV_OSST) += osst.o obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 01c23d27f290..536426f25e86 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -149,12 +149,10 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) if (scsi_bufflen(cmd)) { cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; cmd->SCp.ptr = NULL; cmd->SCp.this_residual = 0; } @@ -163,6 +161,17 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) cmd->SCp.Message = 0; } +static inline void advance_sg_buffer(struct scsi_cmnd *cmd) +{ + struct scatterlist *s = cmd->SCp.buffer; + + if (!cmd->SCp.this_residual && s && !sg_is_last(s)) { + cmd->SCp.buffer = sg_next(s); + cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } +} + /** * NCR5380_poll_politely2 - wait for two chip register values * @hostdata: host private data @@ -272,9 +281,8 @@ mrs[] = { static void NCR5380_print(struct Scsi_Host *instance) { struct NCR5380_hostdata *hostdata = shost_priv(instance); - unsigned char status, data, basr, mr, icr, i; + unsigned char status, basr, mr, icr, i; - data = NCR5380_read(CURRENT_SCSI_DATA_REG); status = NCR5380_read(STATUS_REG); mr = NCR5380_read(MODE_REG); icr = NCR5380_read(INITIATOR_COMMAND_REG); @@ -710,6 +718,8 @@ static void NCR5380_main(struct work_struct *work) NCR5380_information_transfer(instance); done = 0; } + if (!hostdata->connected) + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); spin_unlock_irq(&hostdata->lock); if (!done) cond_resched(); @@ -1111,8 +1121,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) spin_lock_irq(&hostdata->lock); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); - if (!hostdata->connected) - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); goto out; } @@ -1120,7 +1128,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) if (err < 0) { spin_lock_irq(&hostdata->lock); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); /* Can't touch cmd if it has been reclaimed by the scsi ML */ if (!hostdata->selecting) @@ -1158,7 +1165,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) if (err < 0) { shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); goto out; } if (!hostdata->selecting) { @@ -1673,12 +1679,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) sun3_dma_setup_done != cmd) { int count; - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } + advance_sg_buffer(cmd); count = sun3scsi_dma_xfer_len(hostdata, cmd); @@ -1728,15 +1729,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) * scatter-gather list, move onto the next one. */ - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n", - cmd->SCp.this_residual, - cmd->SCp.buffers_residual); - } + advance_sg_buffer(cmd); + dsprintk(NDEBUG_INFORMATION, instance, + "this residual %d, sg ents %d\n", + cmd->SCp.this_residual, + sg_nents(cmd->SCp.buffer)); /* * The preferred transfer method is going to be @@ -1764,10 +1761,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) scmd_printk(KERN_INFO, cmd, "switching to slow handshake\n"); cmd->device->borken = 1; - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - /* XXX - need to source or sink data here, as appropriate */ + do_reset(instance); + bus_reset_cleanup(instance); } } else { /* Transfer a small chunk so that the @@ -1827,9 +1822,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ NCR5380_write(TARGET_COMMAND_REG, 0); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - maybe_release_dma_irq(instance); return; case MESSAGE_REJECT: @@ -1861,8 +1853,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ NCR5380_write(TARGET_COMMAND_REG, 0); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); #ifdef SUN3_SCSI_VME dregs->csr |= CSR_DMA_ENABLE; #endif @@ -1933,13 +1923,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) if (!hostdata->connected) return; - /* Fall through to reject message */ - + /* Reject message */ + /* Fall through */ + default: /* * If we get something weird that we aren't expecting, - * reject it. + * log it. */ - default: if (tmp == EXTENDED_MESSAGE) scmd_printk(KERN_INFO, cmd, "rejecting unknown extended message code %02x, length %d\n", @@ -1965,7 +1955,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); maybe_release_dma_irq(instance); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; } msgout = NOP; @@ -2137,12 +2126,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) if (sun3_dma_setup_done != tmp) { int count; - if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { - ++tmp->SCp.buffer; - --tmp->SCp.buffers_residual; - tmp->SCp.this_residual = tmp->SCp.buffer->length; - tmp->SCp.ptr = sg_virt(tmp->SCp.buffer); - } + advance_sg_buffer(tmp); count = sun3scsi_dma_xfer_len(hostdata, tmp); diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index efca509b92b0..5935fd6d1a05 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -235,7 +235,7 @@ struct NCR5380_cmd { #define NCR5380_PIO_CHUNK_SIZE 256 /* Time limit (ms) to poll registers when IRQs are disabled, e.g. during PDMA */ -#define NCR5380_REG_POLL_TIME 15 +#define NCR5380_REG_POLL_TIME 10 static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr) { diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index c96bc7261a42..564b35473672 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only #include <linux/types.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index dcf435f312dd..222c77c9621f 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only #include <linux/types.h> #include <linux/mm.h> #include <linux/ioport.h> diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index 66c573093901..5e575afce134 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux. * Amiga Technologies A4000T SCSI controller. diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile index 3893b95b140b..8f0eec682bb6 100644 --- a/drivers/scsi/aacraid/Makefile +++ b/drivers/scsi/aacraid/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # Adaptec aacraid obj-$(CONFIG_SCSI_AACRAID) := aacraid.o diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 6085aa087a2f..0ed3f806ace5 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * aachba.c * * Abstract: Contains Interfaces to manage IOs. - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 11fb68d7e60d..3fa03230f6ba 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * aacraid.h * * Abstract: Contains all routines for control of the aacraid driver - * */ #ifndef _AACRAID_H_ diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index f0ff40332753..ffe41bc111fc 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * commctrl.c * * Abstract: Contains all routines for control of the AFA comm layer - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 0dc7b5a4fea2..d4fcfa1e54e0 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,26 +10,11 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * comminit.c * * Abstract: This supports the initialization of the host adapter commuication interface. * This is a platform dependent module for the pci cyclone board. - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 78430a7b294c..2142a649e865 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,26 +10,11 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * commsup.c * * Abstract: Contain all routines that are required for FSA host/adapter * communication. - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 40a771dd1c0e..a557aa629827 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,26 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * dpcsup.c * * Abstract: All DPC processing routines for the cyclone board occur here. - * - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 8e28a505f7e8..644f7f5c61a2 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,20 +10,6 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * linit.c * diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c index c59074e782d6..b5d6b24d6dbd 100644 --- a/drivers/scsi/aacraid/nark.c +++ b/drivers/scsi/aacraid/nark.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * @@ -8,25 +9,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * nark.c * * Abstract: Hardware Device Interface for NEMER/ARK - * */ #include <linux/pci.h> diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index a1bc5bbf7a34..5f2cede4d477 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * rkt.c * * Abstract: Hardware miniport for Drawbridge specific hardware functions. - * */ #include <linux/blkdev.h> diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 576cdf9cc120..3dea348bd25d 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * rx.c * * Abstract: Hardware miniport for Drawbridge specific hardware functions. - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index efa96c1c6aa3..aa5d7638cade 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * sa.c * * Abstract: Drawbridge specific support functions - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index 97bb9e9d201c..3b66e06726c8 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. @@ -9,25 +10,10 @@ * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * * Module Name: * src.c * * Abstract: Hardware Device Interface for PMC SRC based controllers - * */ #include <linux/kernel.h> diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index d37584403c33..a242a62caaa1 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * @@ -6,11 +7,6 @@ * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx> * Copyright (c) 2014 Hannes Reinecke <hare@suse.de> * All Rights Reserved. - * - * 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. */ /* @@ -7714,7 +7710,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */ return ADV_SUCCESS; } - slp++; + slp = sg_next(slp); } sg_block->sg_cnt = NO_OF_SG_PER_BLOCK; prev_sg_block = sg_block; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 97872838b983..eb466c2e1839 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* aha152x.c -- Adaptec AHA-152x driver * Author: Jürgen E. Fischer, fischer@norbit.de * Copyright 1993-2004 Jürgen E. Fischer * - * 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. - * - * * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $ * * $Log: aha152x.c,v $ @@ -228,7 +218,6 @@ * Revision 0.0 1993/08/14 19:54:25 root * empty function bodies; detect() works. * - * ************************************************************************** see Documentation/scsi/aha152x.txt for configuration details @@ -948,7 +937,6 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, SCp.ptr : buffer pointer SCp.this_residual : buffer length SCp.buffer : next buffer - SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ if ((phase & resetting) || !scsi_sglist(SCpnt)) { @@ -956,13 +944,11 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, SCpnt->SCp.this_residual = 0; scsi_set_resid(SCpnt, 0); SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; } else { scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); SCpnt->SCp.buffer = scsi_sglist(SCpnt); SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; } DO_LOCK(flags); @@ -2030,10 +2016,9 @@ static void datai_run(struct Scsi_Host *shpnt) } if (CURRENT_SC->SCp.this_residual == 0 && - CURRENT_SC->SCp.buffers_residual > 0) { + !sg_is_last(CURRENT_SC->SCp.buffer)) { /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; } @@ -2136,10 +2121,10 @@ static void datao_run(struct Scsi_Host *shpnt) CMD_INC_RESID(CURRENT_SC, -2 * data_count); } - if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { + if (CURRENT_SC->SCp.this_residual == 0 && + !sg_is_last(CURRENT_SC->SCp.buffer)) { /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; } @@ -2158,22 +2143,26 @@ static void datao_run(struct Scsi_Host *shpnt) static void datao_end(struct Scsi_Host *shpnt) { if(TESTLO(DMASTAT, DFIFOEMP)) { - int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) - - GETSTCNT(); + u32 datao_cnt = GETSTCNT(); + int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC); + int done; + struct scatterlist *sg = scsi_sglist(CURRENT_SC); - CMD_INC_RESID(CURRENT_SC, data_count); + CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt); - data_count -= CURRENT_SC->SCp.ptr - - SG_ADDRESS(CURRENT_SC->SCp.buffer); - while(data_count>0) { - CURRENT_SC->SCp.buffer--; - CURRENT_SC->SCp.buffers_residual++; - data_count -= CURRENT_SC->SCp.buffer->length; + done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC); + /* Locate the first SG entry not yet sent */ + while (done > 0 && !sg_is_last(sg)) { + if (done < sg->length) + break; + done -= sg->length; + sg = sg_next(sg); } - CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) - - data_count; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + - data_count; + + CURRENT_SC->SCp.buffer = sg; + CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length - + done; } SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); @@ -2501,7 +2490,7 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr) seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", scsi_get_resid(ptr), ptr->SCp.this_residual, - ptr->SCp.buffers_residual); + sg_nents(ptr->SCp.buffer) - 1); if (ptr->SCp.phase & not_issued) seq_puts(m, "not issued|"); diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index ba7a5725be04..dc5667afeb27 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Adaptec AHA-1542 SCSI host adapters * diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index 3b3d599103f8..16743fb9eead 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # AIC79XX 2.5.X Kernel configuration File. # $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $ diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 55ac55ee6068..3546b8cc401f 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -1,9 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only # # AIC7XXX and AIC79XX 2.5.X Kernel configuration File. # $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#7 $ # config SCSI_AIC7XXX - tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" + tristate "Adaptec AIC7xxx Fast -> U160 support" depends on (PCI || EISA) && SCSI select SCSI_SPI_ATTRS ---help--- diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index ba0b411d03e2..00fde2243e48 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -1666,7 +1666,7 @@ scratch_ram { size 6 /* * These are reserved registers in the card's scratch ram on the 2742. - * The EISA configuraiton chip is mapped here. On Rev E. of the + * The EISA configuration chip is mapped here. On Rev E. of the * aic7770, the sequencer can use this area for scratch, but the * host cannot directly access these registers. On later chips, this * area can be read and written by both the host and the sequencer. diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index f3362f4ab16e..a9d40d3b90ef 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -1666,7 +1666,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) printk("\tCRC Value Mismatch\n"); if ((sstat2 & CRCENDERR) != 0) printk("\tNo terminal CRC packet " - "recevied\n"); + "received\n"); if ((sstat2 & CRCREQERR) != 0) printk("\tIllegal CRC packet " "request\n"); @@ -4920,24 +4920,30 @@ ahc_fini_scbdata(struct ahc_softc *ahc) } ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); } + /* fall through */ case 6: ahc_dmamap_unload(ahc, scb_data->sense_dmat, scb_data->sense_dmamap); + /* fall through */ case 5: ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, scb_data->sense_dmamap); ahc_dmamap_destroy(ahc, scb_data->sense_dmat, scb_data->sense_dmamap); + /* fall through */ case 4: ahc_dma_tag_destroy(ahc, scb_data->sense_dmat); + /* fall through */ case 3: ahc_dmamap_unload(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap); + /* fall through */ case 2: ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, scb_data->hscb_dmamap); ahc_dmamap_destroy(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap); + /* fall through */ case 1: ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat); break; @@ -6002,8 +6008,8 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, if ((scb->flags & SCB_ACTIVE) == 0) printk("Inactive SCB in Waiting List\n"); ahc_done(ahc, scb); - /* FALLTHROUGH */ } + /* fall through */ case SEARCH_REMOVE: next = ahc_rem_wscb(ahc, next, prev); break; @@ -7008,8 +7014,8 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) } address -= address_offset; fmt3_ins->address = address; - /* FALLTHROUGH */ } + /* fall through */ case AIC_OP_OR: case AIC_OP_AND: case AIC_OP_XOR: @@ -7035,7 +7041,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) fmt1_ins->opcode = AIC_OP_AND; fmt1_ins->immediate = 0xff; } - /* FALLTHROUGH */ + /* fall through */ case AIC_OP_ROL: if ((ahc->features & AHC_ULTRA2) != 0) { int i, count; diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig index c83fe751d0bb..71931c371b1c 100644 --- a/drivers/scsi/aic94xx/Kconfig +++ b/drivers/scsi/aic94xx/Kconfig @@ -1,28 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Kernel configuration file for aic94xx SAS/SATA driver. # # Copyright (c) 2005 Adaptec, Inc. All rights reserved. # Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com> # -# This file is licensed under GPLv2. -# -# This file is part of the aic94xx driver. -# -# The aic94xx driver 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; version 2 of the -# License. -# -# The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# config SCSI_AIC94XX tristate "Adaptec AIC94xx SAS/SATA support" diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile index c0a15c754585..db9fbe3a8e4c 100644 --- a/drivers/scsi/aic94xx/Makefile +++ b/drivers/scsi/aic94xx/Makefile @@ -1,26 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for Adaptec aic94xx SAS/SATA driver. # # Copyright (C) 2005 Adaptec, Inc. All rights reserved. # Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> # -# This file is licensed under GPLv2. -# -# This file is part of the aic94xx driver. -# -# The aic94xx driver 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; version 2 of the -# License. -# -# The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ccflags-$(CONFIG_AIC94XX_DEBUG) := -DASD_DEBUG -DASD_ENTER_EXIT diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index 26d4ad9ede2e..c23bbb609126 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver header file. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * * $Id: //depot/aic94xx/aic94xx.h#31 $ */ diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 33072388ea16..604a5331f639 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -1,27 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA DDB management * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * * $Id: //depot/aic94xx/aic94xx_dev.c#21 $ */ @@ -187,9 +170,7 @@ static int asd_init_target_ddb(struct domain_device *dev) } } else { flags |= CONCURRENT_CONN_SUPP; - if (!dev->parent && - (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || - dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)) + if (!dev->parent && dev_is_expander(dev->dev_type)) asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN, 4); else diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c index a16a77c8b9cf..7c4c53a54b78 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.c +++ b/drivers/scsi/aic94xx/aic94xx_dump.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver dump interface. * @@ -5,28 +6,9 @@ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com> * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * * 2005/07/14/LT Complete overhaul of this file. Update pages, register * locations, names, etc. Make use of macros. Print more information. * Print all cseq and lseq mip and mdp. - * */ #include <linux/pci.h> diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h index 191a753d42a7..d8faa5db1998 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.h +++ b/drivers/scsi/aic94xx/aic94xx_dump.h @@ -1,27 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver dump header file. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef _AIC94XX_DUMP_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 2bc7615193bd..c5a46c59d4f8 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -1,27 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver hardware interface. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/pci.h> diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index 8f147e720cfd..930e192b1cd4 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -1,27 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver hardware interface header file. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef _AIC94XX_HWI_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index bbdae67774f0..261d8e495fed 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -1,27 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver initialization. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/module.h> diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c index 56b17c22526e..392499e80821 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg.c +++ b/drivers/scsi/aic94xx/aic94xx_reg.c @@ -1,27 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver register access. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/pci.h> diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h index 2279307fd27e..d1c0975f8df3 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg.h +++ b/drivers/scsi/aic94xx/aic94xx_reg.h @@ -1,27 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver hardware registers definitions. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef _AIC94XX_REG_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index dd6cc8008b16..b96cfc33bb8f 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver hardware registers definitions. * @@ -9,26 +10,7 @@ * agnostic register r/w functions. Some register corrections, sizes, * etc. * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $ - * */ #ifndef _ADP94XX_REG_DEF_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h index 101072cab70f..3fe34cb96bb1 100644 --- a/drivers/scsi/aic94xx/aic94xx_sas.h +++ b/drivers/scsi/aic94xx/aic94xx_sas.h @@ -1,27 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef _AIC94XX_SAS_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 91ea87dfb700..4a80ec08f0c9 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -1,27 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver SCB management. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/gfp.h> diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index c831e30411fa..3ddc8852bc32 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -1,28 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver access to shared data structures and memory * maps. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/pci.h> diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h index a06dc0114b8c..80f3c4782725 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.h +++ b/drivers/scsi/aic94xx/aic94xx_sds.h @@ -1,27 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver hardware interface header file. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Gilbert Wu <gilbert_wu@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef _AIC94XX_SDS_H_ #define _AIC94XX_SDS_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index da1e0568510d..11853ec29d87 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA driver sequencer interface. * @@ -5,25 +6,6 @@ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * * Parts of this code adapted from David Chaw's adp94xx_seq.c. - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/delay.h> diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index ad787c55525f..5bf9b8ae6a87 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h @@ -1,27 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Aic94xx SAS/SATA driver sequencer interface header file. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef _AIC94XX_SEQ_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 7fea344531f6..f923ed019d4a 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -1,27 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx SAS/SATA Tasks * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/spinlock.h> diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 2a01702d5ba7..f814026f26fa 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -1,27 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Aic94xx Task Management Functions * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver 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; version 2 of the - * License. - * - * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/spinlock.h> diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c index 27c0a4a937d9..b69edb473295 100644 --- a/drivers/scsi/am53c974.c +++ b/drivers/scsi/am53c974.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AMD am53c974 driver. * Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH diff --git a/drivers/scsi/arcmsr/Makefile b/drivers/scsi/arcmsr/Makefile index 721aced39168..9051f66cae36 100644 --- a/drivers/scsi/arcmsr/Makefile +++ b/drivers/scsi/arcmsr/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # File: drivers/arcmsr/Makefile # Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver. diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig index cfd172a439c9..f34badc75196 100644 --- a/drivers/scsi/arm/Kconfig +++ b/drivers/scsi/arm/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # SCSI driver configuration for Acorn # diff --git a/drivers/scsi/arm/acornscsi-io.S b/drivers/scsi/arm/acornscsi-io.S index 22171b2110a8..fdd7237bb829 100644 --- a/drivers/scsi/arm/acornscsi-io.S +++ b/drivers/scsi/arm/acornscsi-io.S @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/linkage.h> diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index d7509859dc00..d12dd89538df 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/acornscsi.c * * Acorn SCSI 3 driver * By R.M.King. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Abandoned using the Select and Transfer command since there were * some nasty races between our software and the target devices that * were not easy to solve, and the device errata had a lot of entries diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h index 01bc715a3aec..376c76bc2aca 100644 --- a/drivers/scsi/arm/acornscsi.h +++ b/drivers/scsi/arm/acornscsi.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/acornscsi.h * * Copyright (C) 1997 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Acorn SCSI driver */ #ifndef ACORNSCSI_H diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index 5e9dd9f34821..591414120754 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/scsi/arm/arxescsi.c * diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index e2d2a81d8e0b..3fd944374631 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic Generic NCR5380 driver * diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 40afcbd8de61..a1f3e9ee4e63 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/cumana_2.c * * Copyright (C) 1997-2005 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Changelog: * 30-08-1997 RMK 0.0.0 Created, READONLY version. * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 8f64c370a8a7..134f040d58e2 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/eesox.c * * Copyright (C) 1997-2005 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver is based on experimentation. Hence, it may have made * assumptions about the particular card that I have available, and * may not be reliable! diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 27bda2b05de6..aea4fd73c862 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/fas216.c * * Copyright (C) 1997-2003 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and * other sources, including: * the AMD Am53CF94 data sheet diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index c57c16ef8193..847413ce14cf 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/fas216.h * * Copyright (C) 1997-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * FAS216 generic driver */ #ifndef FAS216_H diff --git a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c index 7c95c7582b29..58115831362f 100644 --- a/drivers/scsi/arm/msgqueue.c +++ b/drivers/scsi/arm/msgqueue.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/msgqueue.c * * Copyright (C) 1997-1998 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * message queue handling */ #include <linux/module.h> diff --git a/drivers/scsi/arm/msgqueue.h b/drivers/scsi/arm/msgqueue.h index 41c7333df3e3..4bcc400f556b 100644 --- a/drivers/scsi/arm/msgqueue.h +++ b/drivers/scsi/arm/msgqueue.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/msgqueue.h * * Copyright (C) 1997 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * message queue handling */ #ifndef MSGQUEUE_H diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c index 8f2efaab8d46..7c9d361e91a9 100644 --- a/drivers/scsi/arm/oak.c +++ b/drivers/scsi/arm/oak.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Oak Generic NCR5380 driver * diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 759f95ba993c..c795537a671c 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/powertec.c * * Copyright (C) 1997-2005 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/blkdev.h> diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c index 996dfe903928..e5559f27669d 100644 --- a/drivers/scsi/arm/queue.c +++ b/drivers/scsi/arm/queue.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/queue.c: queue handling primitives * * Copyright (C) 1997-2000 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Changelog: * 15-Sep-1997 RMK Created. * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h index 3c519c9237b2..cb51379dce94 100644 --- a/drivers/scsi/arm/queue.h +++ b/drivers/scsi/arm/queue.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/queue.h: queue handling * * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef QUEUE_H #define QUEUE_H diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 138a521ba1a8..4d5ff7b4e864 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/drivers/acorn/scsi/scsi.h * * Copyright (C) 2002 Russell King * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Commonly used scsi driver functions. */ diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 1267200380f8..e41f0bbdc9fd 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski @@ -194,12 +195,11 @@ static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12); ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13); ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14); - if (dev->id[c][target_id].last_len != adrcnt) - { - k = dev->id[c][target_id].last_len; + if (dev->id[c][target_id].last_len != adrcnt) { + k = dev->id[c][target_id].last_len; k -= adrcnt; dev->id[c][target_id].tran_len = k; - dev->id[c][target_id].last_len = adrcnt; + dev->id[c][target_id].last_len = adrcnt; } #ifdef ED_DBGP printk("dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len); diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig index bad5f32e1f67..958c9b46ec78 100644 --- a/drivers/scsi/be2iscsi/Kconfig +++ b/drivers/scsi/be2iscsi/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config BE2ISCSI tristate "Emulex 10Gbps iSCSI - BladeEngine 2" depends on PCI && SCSI && NET diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile index d0488eaafc25..910885343a75 100644 --- a/drivers/scsi/be2iscsi/Makefile +++ b/drivers/scsi/be2iscsi/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile to build the iSCSI driver for Emulex OneConnect. # diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index e035acf56652..4c58a02590c7 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,15 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2017 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * * Contact Information: * linux-drivers@broadcom.com - * */ #ifndef BEISCSI_H diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 0a6972ee94d7..69b1a80e3687 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * * Contact Information: * linux-drivers@broadcom.com - * */ #include <scsi/iscsi_proto.h> @@ -963,7 +958,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, * @ctrl: ptr to ctrl_info * @cq: Completion Queue * @dq: Default Queue - * @lenght: ring size + * @length: ring size * @entry_size: size of each entry in DEFQ * @is_header: Header or Data DEFQ * @ulp_num: Bind to which ULP diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 6f05d1dfa10a..063dccc18f70 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,15 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2017 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * * Contact Information: * linux-drivers@broadcom.com - * */ #ifndef BEISCSI_CMDS_H diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 96b96e2ab91a..2058d50d62e1 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI * Host Bus Adapters. Refer to the README file included with this package @@ -6,13 +7,8 @@ * Copyright (c) 2018 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as published - * by the Free Software Foundation. - * * Contact Information: * linux-drivers@broadcom.com - * */ #include <scsi/libiscsi.h> @@ -679,6 +675,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, case ISCSI_PARAM_MAX_XMIT_DLENGTH: if (conn->max_xmit_dlength > 65536) conn->max_xmit_dlength = 65536; + /* fall through */ default: return 0; } diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index f41dfda97e17..8c88657eed0d 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,15 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2017 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * * Contact Information: * linux-drivers@broadcom.com - * */ #ifndef _BE_ISCSI_ diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 76e49d902609..0760d0bd8a10 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1532,6 +1532,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, break; case UNSOL_DATA_DIGEST_ERROR_NOTIFY: error = 1; + /* fall through */ case UNSOL_DATA_NOTIFY: pasync_handle = pasync_ctx->async_entry[ci].data; break; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 42bb6bdb68bd..98977c0700f1 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,15 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2017 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * * Contact Information: * linux-drivers@broadcom.com - * */ #ifndef _BEISCSI_MAIN_ diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 0b22c99a7a22..d10858828701 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,15 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2017 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * * Contact Information: * linux-drivers@broadcom.com - * */ #ifndef _BEISCSI_MGMT_ diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h index 0e119d838e1b..7bd2ba1ad4d1 100644 --- a/drivers/scsi/bfa/bfa.h +++ b/drivers/scsi/bfa/bfa.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_H__ #define __BFA_H__ @@ -62,8 +54,7 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \ writel((__bfa)->iocfc.req_cq_pi[__reqq], \ (__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq]); \ - mmiowb(); \ - } while (0) + } while (0) #define bfa_rspq_pi(__bfa, __rspq) \ (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)) diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 10a63be92544..0f554ebb8f2c 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h index 9685efc59b16..6b606bf589b4 100644 --- a/drivers/scsi/bfa/bfa_cs.h +++ b/drivers/scsi/bfa/bfa_cs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h index 5dc3782d615b..6abd9f42a3fc 100644 --- a/drivers/scsi/bfa/bfa_defs.h +++ b/drivers/scsi/bfa/bfa_defs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_DEFS_H__ diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h index 5815a904574d..5e36620425ac 100644 --- a/drivers/scsi/bfa/bfa_defs_fcs.h +++ b/drivers/scsi/bfa/bfa_defs_fcs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_DEFS_FCS_H__ diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h index c19c26e0e405..8439951d95ac 100644 --- a/drivers/scsi/bfa/bfa_defs_svc.h +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_DEFS_SVC_H__ diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h index 18b7304d6b0b..b00fb2409c50 100644 --- a/drivers/scsi/bfa/bfa_fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_FC_H__ diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c index 2de5d514e99c..df18d9d2af53 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.c +++ b/drivers/scsi/bfa/bfa_fcbuild.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* * fcbuild.c - FC link service frame building and parsing routines diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h index ac08d0b5b89a..49e0ee4a7334 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.h +++ b/drivers/scsi/bfa/bfa_fcbuild.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* * fcbuild.h - FC link service frame building and parsing routines diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 2c85f5b1f9c1..284baa3b0c8e 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" @@ -2586,6 +2578,7 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) case FCP_IODIR_RW: bfa_stats(itnim, input_reqs); bfa_stats(itnim, output_reqs); + /* fall through */ default: bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); } @@ -2820,6 +2813,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) case BFI_IOIM_STS_TIMEDOUT: bfa_stats(ioim->itnim, iocomp_timedout); + /* fall through */ case BFI_IOIM_STS_ABORTED: rsp->io_status = BFI_IOIM_STS_ABORTED; bfa_stats(ioim->itnim, iocomp_aborted); @@ -3215,9 +3209,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, switch (event) { case BFA_TSKIM_SM_DONE: bfa_reqq_wcancel(&tskim->reqq_wait); - /* - * Fall through !!! - */ + /* fall through */ case BFA_TSKIM_SM_QRESUME: bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); bfa_tskim_send_abort(tskim); diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index ec8f863540ae..8bf09433549b 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_FCPIM_H__ diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 932feb0ed4da..d2d396ca0e9a 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index e60f72b766ea..3e117fed95c9 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_FCS_H__ diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c index 2e3b19e7e079..c7de62baeec9 100644 --- a/drivers/scsi/bfa/bfa_fcs_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 646f09f66443..7c3eadc58b98 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index 1e400f2aaece..82801b366500 100644 --- a/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c index c4a0c0eb88a5..6cc2f7290d7e 100644 --- a/drivers/scsi/bfa/bfa_hw_cb.c +++ b/drivers/scsi/bfa/bfa_hw_cb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" @@ -61,7 +53,6 @@ bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq, u32 ci) bfa_rspq_ci(bfa, rspq) = ci; writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); } void @@ -72,7 +63,6 @@ bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci) bfa_rspq_ci(bfa, rspq) = ci; writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); } void diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c index b0ff378dece2..4b1c0a568a22 100644 --- a/drivers/scsi/bfa/bfa_hw_ct.c +++ b/drivers/scsi/bfa/bfa_hw_ct.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" @@ -81,7 +73,6 @@ bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci) bfa_rspq_ci(bfa, rspq) = ci; writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); } /* @@ -94,7 +85,6 @@ bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci) { bfa_rspq_ci(bfa, rspq) = ci; writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); } void diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 79a55c3615be..93471d7c61d0 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 0f9fab770339..933a1c3890ff 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_IOC_H__ diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c index f1b80da298c8..2fc6215c2b2b 100644 --- a/drivers/scsi/bfa/bfa_ioc_cb.c +++ b/drivers/scsi/bfa/bfa_ioc_cb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 651a8fb93037..18b58b2f304f 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h index 1c2ab395e616..578e7678b056 100644 --- a/drivers/scsi/bfa/bfa_modules.h +++ b/drivers/scsi/bfa/bfa_modules.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h index da570c0b8275..0ed67339ed90 100644 --- a/drivers/scsi/bfa/bfa_plog.h +++ b/drivers/scsi/bfa/bfa_plog.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_PORTLOG_H__ #define __BFA_PORTLOG_H__ diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c index 079bc77f4102..4511ec865f06 100644 --- a/drivers/scsi/bfa/bfa_port.c +++ b/drivers/scsi/bfa/bfa_port.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h index 0c3b200243ca..7e569d4b5214 100644 --- a/drivers/scsi/bfa/bfa_port.h +++ b/drivers/scsi/bfa/bfa_port.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_PORT_H__ diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index 6fc34fb20f00..6d2131441f0a 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 "bfad_drv.h" diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 7e8fb6231d49..9c83109574e9 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFA_SVC_H__ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 88880a66a189..2f9213b257a4 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 26b0fa4e90b5..29ab81df75c0 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index d8e6d7480f35..a76c968dbac5 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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/uaccess.h> diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h index 917e140dfbcc..e525339df4ae 100644 --- a/drivers/scsi/bfa/bfad_bsg.h +++ b/drivers/scsi/bfa/bfad_bsg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 BFAD_BSG_H #define BFAD_BSG_H diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index bfcd87c0dc74..fd1b378a263a 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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/debugfs.h> diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 4fe980a6441f..eaee7c8bc2d2 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 394930cbaa13..b2014cb96f58 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index bd4ac187fd8e..f16d4b219e44 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFAD_IM_H__ diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h index 5f698d038b21..41e6b4dac056 100644 --- a/drivers/scsi/bfa/bfi.h +++ b/drivers/scsi/bfa/bfi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFI_H__ diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h index ccbd9e31a5de..b9dc0b9bb814 100644 --- a/drivers/scsi/bfa/bfi_ms.h +++ b/drivers/scsi/bfa/bfi_ms.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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 __BFI_MS_H__ diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h index fd5b87616e8b..0803b710a26e 100644 --- a/drivers/scsi/bfa/bfi_reg.h +++ b/drivers/scsi/bfa/bfi_reg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. * Copyright (c) 2014- QLogic Corporation. @@ -5,15 +6,6 @@ * www.qlogic.com * * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * 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. */ /* diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig index d401a096dfc7..e0ccb48ec961 100644 --- a/drivers/scsi/bnx2fc/Kconfig +++ b/drivers/scsi/bnx2fc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_BNX2X_FCOE tristate "QLogic FCoE offload support" depends on PCI diff --git a/drivers/scsi/bnx2fc/Makefile b/drivers/scsi/bnx2fc/Makefile index 141149e8cdad..1d72e279a97d 100644 --- a/drivers/scsi/bnx2fc/Makefile +++ b/drivers/scsi/bnx2fc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o \ diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 901a31632493..3b84db8d13a9 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -66,7 +66,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "2.11.8" +#define BNX2FC_VERSION "2.12.10" #define PFX "bnx2fc: " @@ -75,8 +75,9 @@ #define BNX2X_DOORBELL_PCI_BAR 2 #define BNX2FC_MAX_BD_LEN 0xffff -#define BNX2FC_BD_SPLIT_SZ 0x8000 -#define BNX2FC_MAX_BDS_PER_CMD 256 +#define BNX2FC_BD_SPLIT_SZ 0xffff +#define BNX2FC_MAX_BDS_PER_CMD 255 +#define BNX2FC_FW_MAX_BDS_PER_CMD 255 #define BNX2FC_SQ_WQES_MAX 256 @@ -433,8 +434,10 @@ struct bnx2fc_cmd { void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg); struct bnx2fc_els_cb_arg *cb_arg; struct delayed_work timeout_work; /* timer for ULP timeouts */ - struct completion tm_done; - int wait_for_comp; + struct completion abts_done; + struct completion cleanup_done; + int wait_for_abts_comp; + int wait_for_cleanup_comp; u16 xid; struct fcoe_err_report_entry err_entry; struct fcoe_task_ctx_entry *task; @@ -455,6 +458,7 @@ struct bnx2fc_cmd { #define BNX2FC_FLAG_ELS_TIMEOUT 0xb #define BNX2FC_FLAG_CMD_LOST 0xc #define BNX2FC_FLAG_SRR_SENT 0xd +#define BNX2FC_FLAG_ISSUE_CLEANUP_REQ 0xe u8 rec_retry; u8 srr_retry; u32 srr_offset; diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 76e65a32f38c..754f2e82d955 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -610,7 +610,6 @@ int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req) rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec), bnx2fc_rec_compl, cb_arg, r_a_tov); -rec_err: if (rc) { BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n"); spin_lock_bh(&tgt->tgt_lock); @@ -618,6 +617,7 @@ rec_err: spin_unlock_bh(&tgt->tgt_lock); kfree(cb_arg); } +rec_err: return rc; } @@ -654,7 +654,6 @@ int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl) rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr), bnx2fc_srr_compl, cb_arg, r_a_tov); -srr_err: if (rc) { BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n"); spin_lock_bh(&tgt->tgt_lock); @@ -664,6 +663,7 @@ srr_err: } else set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags); +srr_err: return rc; } @@ -854,33 +854,57 @@ void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, kref_put(&els_req->refcount, bnx2fc_cmd_release); } +#define BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC 1 +#define BNX2FC_FCOE_MAC_METHOD_FCF_MAP 2 +#define BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC 3 static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) { struct fcoe_ctlr *fip = arg; struct fc_exch *exch = fc_seq_exch(seq); struct fc_lport *lport = exch->lp; - u8 *mac; - u8 op; + + struct fc_frame_header *fh; + u8 *granted_mac; + u8 fcoe_mac[6]; + u8 fc_map[3]; + int method; if (IS_ERR(fp)) goto done; - mac = fr_cb(fp)->granted_mac; - if (is_zero_ether_addr(mac)) { - op = fc_frame_payload_op(fp); - if (lport->vport) { - if (op == ELS_LS_RJT) { - printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n"); - fc_vport_terminate(lport->vport); - fc_frame_free(fp); - return; - } - } - fcoe_ctlr_recv_flogi(fip, lport, fp); + fh = fc_frame_header_get(fp); + granted_mac = fr_cb(fp)->granted_mac; + + /* + * We set the source MAC for FCoE traffic based on the Granted MAC + * address from the switch. + * + * If granted_mac is non-zero, we use that. + * If the granted_mac is zeroed out, create the FCoE MAC based on + * the sel_fcf->fc_map and the d_id fo the FLOGI frame. + * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the + * d_id of the FLOGI frame. + */ + if (!is_zero_ether_addr(granted_mac)) { + ether_addr_copy(fcoe_mac, granted_mac); + method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC; + } else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) { + hton24(fc_map, fip->sel_fcf->fc_map); + fcoe_mac[0] = fc_map[0]; + fcoe_mac[1] = fc_map[1]; + fcoe_mac[2] = fc_map[2]; + fcoe_mac[3] = fh->fh_d_id[0]; + fcoe_mac[4] = fh->fh_d_id[1]; + fcoe_mac[5] = fh->fh_d_id[2]; + method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP; + } else { + fc_fcoe_set_mac(fcoe_mac, fh->fh_d_id); + method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC; } - if (!is_zero_ether_addr(mac)) - fip->update_mac(lport, mac); + + BNX2FC_HBA_DBG(lport, "fcoe_mac=%pM method=%d\n", fcoe_mac, method); + fip->update_mac(lport, fcoe_mac); done: fc_lport_flogi_resp(seq, fp, lport); } diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index a75e74ad1698..7796799bf04a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2971,7 +2971,8 @@ static struct scsi_host_template bnx2fc_shost_template = { .this_id = -1, .cmd_per_lun = 3, .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, - .max_sectors = 1024, + .dma_boundary = 0x7fff, + .max_sectors = 0x3fbf, .track_queue_depth = 1, .slave_configure = bnx2fc_slave_configure, .shost_attrs = bnx2fc_host_attrs, diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 039328d9ef13..747f019fb393 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -830,7 +830,7 @@ ret_err_rqe: ((u64)err_entry->data.err_warn_bitmap_hi << 32) | (u64)err_entry->data.err_warn_bitmap_lo; for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { - if (err_warn_bit_map & (u64) (1 << i)) { + if (err_warn_bit_map & ((u64)1 << i)) { err_warn = i; break; } @@ -991,7 +991,6 @@ void bnx2fc_arm_cq(struct bnx2fc_rport *tgt) FCOE_CQE_TOGGLE_BIT_SHIFT); msg = *((u32 *)rx_db); writel(cpu_to_le32(msg), tgt->ctx_base); - mmiowb(); } @@ -1409,7 +1408,6 @@ void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt) (tgt->sq_curr_toggle_bit << 15); msg = *((u32 *)sq_db); writel(cpu_to_le32(msg), tgt->ctx_base); - mmiowb(); } diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index bc9f2a2365f4..9e50e5b53763 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -70,7 +70,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) &io_req->req_flags)) { /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort timed out\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { /* Handle internally generated ABTS timeout */ @@ -775,31 +775,32 @@ retry_tmf: io_req->on_tmf_queue = 1; list_add_tail(&io_req->link, &tgt->active_tm_queue); - init_completion(&io_req->tm_done); - io_req->wait_for_comp = 1; + init_completion(&io_req->abts_done); + io_req->wait_for_abts_comp = 1; /* Ring doorbell */ bnx2fc_ring_doorbell(tgt); spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, + rc = wait_for_completion_timeout(&io_req->abts_done, interface->tm_timeout * HZ); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_abts_comp = 0; if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) { set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); if (io_req->on_tmf_queue) { list_del_init(&io_req->link); io_req->on_tmf_queue = 0; } - io_req->wait_for_comp = 1; + io_req->wait_for_cleanup_comp = 1; + init_completion(&io_req->cleanup_done); bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, + rc = wait_for_completion_timeout(&io_req->cleanup_done, BNX2FC_FW_TIMEOUT); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_cleanup_comp = 0; if (!rc) kref_put(&io_req->refcount, bnx2fc_cmd_release); } @@ -1047,6 +1048,9 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) /* Obtain free SQ entry */ bnx2fc_add_2_sq(tgt, xid); + /* Set flag that cleanup request is pending with the firmware */ + set_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags); + /* Ring doorbell */ bnx2fc_ring_doorbell(tgt); @@ -1083,10 +1087,10 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) { struct bnx2fc_rport *tgt = io_req->tgt; - int rc = SUCCESS; unsigned int time_left; - io_req->wait_for_comp = 1; + init_completion(&io_req->cleanup_done); + io_req->wait_for_cleanup_comp = 1; bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); @@ -1095,22 +1099,22 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) * Can't wait forever on cleanup response lest we let the SCSI error * handler wait forever */ - time_left = wait_for_completion_timeout(&io_req->tm_done, + time_left = wait_for_completion_timeout(&io_req->cleanup_done, BNX2FC_FW_TIMEOUT); - io_req->wait_for_comp = 0; - if (!time_left) + if (!time_left) { BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n", __func__); - /* - * Release reference held by SCSI command the cleanup completion - * hits the BNX2FC_CLEANUP case in bnx2fc_process_cq_compl() and - * thus the SCSI command is not returnedi by bnx2fc_scsi_done(). - */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); + /* + * Put the extra reference to the SCSI command since it would + * not have been returned in this case. + */ + kref_put(&io_req->refcount, bnx2fc_cmd_release); + } spin_lock_bh(&tgt->tgt_lock); - return rc; + io_req->wait_for_cleanup_comp = 0; + return SUCCESS; } /** @@ -1198,7 +1202,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Move IO req to retire queue */ list_add_tail(&io_req->link, &tgt->io_retire_queue); - init_completion(&io_req->tm_done); + init_completion(&io_req->abts_done); + init_completion(&io_req->cleanup_done); if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " @@ -1226,26 +1231,28 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); - io_req->wait_for_comp = 1; + io_req->wait_for_abts_comp = 1; rc = bnx2fc_initiate_abts(io_req); if (rc == FAILED) { + io_req->wait_for_cleanup_comp = 1; bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - wait_for_completion(&io_req->tm_done); + wait_for_completion(&io_req->cleanup_done); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_cleanup_comp = 0; goto done; } spin_unlock_bh(&tgt->tgt_lock); /* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */ - time_left = wait_for_completion_timeout(&io_req->tm_done, - (2 * rp->r_a_tov + 1) * HZ); + time_left = wait_for_completion_timeout(&io_req->abts_done, + (2 * rp->r_a_tov + 1) * HZ); if (time_left) - BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for tm_done"); + BNX2FC_IO_DBG(io_req, + "Timed out in eh_abort waiting for abts_done"); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_abts_comp = 0; if (test_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) { BNX2FC_IO_DBG(io_req, "IO completed in a different context\n"); rc = SUCCESS; @@ -1320,10 +1327,29 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl " "refcnt = %d, cmd_type = %d\n", kref_read(&io_req->refcount), io_req->cmd_type); + /* + * Test whether there is a cleanup request pending. If not just + * exit. + */ + if (!test_and_clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, + &io_req->req_flags)) + return; + /* + * If we receive a cleanup completion for this request then the + * firmware will not give us an abort completion for this request + * so clear any ABTS pending flags. + */ + if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags) && + !test_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) { + set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); + } + bnx2fc_scsi_done(io_req, DID_ERROR); kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); + if (io_req->wait_for_cleanup_comp) + complete(&io_req->cleanup_done); } void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, @@ -1347,6 +1373,16 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, return; } + /* + * If we receive an ABTS completion here then we will not receive + * a cleanup completion so clear any cleanup pending flags. + */ + if (test_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags)) { + clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags); + if (io_req->wait_for_cleanup_comp) + complete(&io_req->cleanup_done); + } + /* Do not issue RRQ as this IO is already cleanedup */ if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags)) @@ -1391,10 +1427,10 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, bnx2fc_cmd_timer_set(io_req, r_a_tov); io_compl: - if (io_req->wait_for_comp) { + if (io_req->wait_for_abts_comp) { if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags)) - complete(&io_req->tm_done); + complete(&io_req->abts_done); } else { /* * We end up here when ABTS is issued as @@ -1578,9 +1614,9 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, sc_cmd->scsi_done(sc_cmd); kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) { + if (io_req->wait_for_abts_comp) { BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } } @@ -1624,6 +1660,7 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) u64 addr; int i; + WARN_ON(scsi_sg_count(sc) > BNX2FC_MAX_BDS_PER_CMD); /* * Use dma_map_sg directly to ensure we're using the correct * dev struct off of pcidev. @@ -1671,6 +1708,16 @@ static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) } io_req->bd_tbl->bd_valid = bd_count; + /* + * Return the command to ML if BD count exceeds the max number + * that can be handled by FW. + */ + if (bd_count > BNX2FC_FW_MAX_BDS_PER_CMD) { + pr_err("bd_count = %d exceeded FW supported max BD(255), task_id = 0x%x\n", + bd_count, io_req->xid); + return -ENOMEM; + } + return 0; } @@ -1927,10 +1974,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, * between command abort and (late) completion. */ BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n"); - if (io_req->wait_for_comp) + if (io_req->wait_for_abts_comp) if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags)) - complete(&io_req->tm_done); + complete(&io_req->abts_done); } bnx2fc_unmap_sg_list(io_req); diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index d735e87e416a..50384b4a817c 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -187,7 +187,7 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort for IO " "cleaned up\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ @@ -210,8 +210,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) list_del_init(&io_req->link); io_req->on_tmf_queue = 0; BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n"); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); } list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) { @@ -251,8 +251,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort for IO " "in retire_q\n"); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); } kref_put(&io_req->refcount, bnx2fc_cmd_release); } diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig index ba30ff86d581..702dc82c9501 100644 --- a/drivers/scsi/bnx2i/Kconfig +++ b/drivers/scsi/bnx2i/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_BNX2_ISCSI tristate "QLogic NetXtreme II iSCSI support" depends on NET diff --git a/drivers/scsi/bnx2i/Makefile b/drivers/scsi/bnx2i/Makefile index b5802bd2e76a..25378671bb1e 100644 --- a/drivers/scsi/bnx2i/Makefile +++ b/drivers/scsi/bnx2i/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index fae6f71e677d..12666313b937 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -253,7 +253,6 @@ void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count) writew(ep->qp.rq_prod_idx, ep->qp.ctx_base + CNIC_RECV_DOORBELL); } - mmiowb(); } @@ -279,8 +278,6 @@ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) bnx2i_ring_577xx_doorbell(bnx2i_conn); } else writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL); - - mmiowb(); /* flush posted PCI writes */ } diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index 0f846ae2f918..8d72b25535c5 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux. * diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 1c5051b1c125..5f8153c37f77 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI Media Changer device driver for Linux 2.6 * diff --git a/drivers/scsi/csiostor/Kconfig b/drivers/scsi/csiostor/Kconfig index 7c7e5085968b..c6c03f9e3798 100644 --- a/drivers/scsi/csiostor/Kconfig +++ b/drivers/scsi/csiostor/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_CHELSIO_FCOE tristate "Chelsio Communications FCoE support" depends on PCI && SCSI diff --git a/drivers/scsi/csiostor/csio_isr.c b/drivers/scsi/csiostor/csio_isr.c index 7c8814715711..b2540402fafc 100644 --- a/drivers/scsi/csiostor/csio_isr.c +++ b/drivers/scsi/csiostor/csio_isr.c @@ -474,13 +474,39 @@ csio_reduce_sqsets(struct csio_hw *hw, int cnt) csio_dbg(hw, "Reduced sqsets to %d\n", hw->num_sqsets); } +static void csio_calc_sets(struct irq_affinity *affd, unsigned int nvecs) +{ + struct csio_hw *hw = affd->priv; + u8 i; + + if (!nvecs) + return; + + if (nvecs < hw->num_pports) { + affd->nr_sets = 1; + affd->set_size[0] = nvecs; + return; + } + + affd->nr_sets = hw->num_pports; + for (i = 0; i < hw->num_pports; i++) + affd->set_size[i] = nvecs / hw->num_pports; +} + static int csio_enable_msix(struct csio_hw *hw) { int i, j, k, n, min, cnt; int extra = CSIO_EXTRA_VECS; struct csio_scsi_cpu_info *info; - struct irq_affinity desc = { .pre_vectors = 2 }; + struct irq_affinity desc = { + .pre_vectors = CSIO_EXTRA_VECS, + .calc_sets = csio_calc_sets, + .priv = hw, + }; + + if (hw->num_pports > IRQ_AFFINITY_MAX_SETS) + return -ENOSPC; min = hw->num_pports + extra; cnt = hw->num_sqsets + extra; diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index 66bbd21819ae..03bd896cdbb9 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -808,6 +808,7 @@ csio_wr_destroy_queues(struct csio_hw *hw, bool cmd) csio_q_eqid(hw, i) = CSIO_MAX_QID; } + /* fall through */ case CSIO_INGRESS: if (csio_q_iqid(hw, i) != CSIO_MAX_QID) { csio_wr_cleanup_iq_ftr(hw, i); diff --git a/drivers/scsi/cxgbi/Kconfig b/drivers/scsi/cxgbi/Kconfig index 17eb5d522f42..75f9428a8a14 100644 --- a/drivers/scsi/cxgbi/Kconfig +++ b/drivers/scsi/cxgbi/Kconfig @@ -1,2 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only source "drivers/scsi/cxgbi/cxgb3i/Kconfig" source "drivers/scsi/cxgbi/cxgb4i/Kconfig" diff --git a/drivers/scsi/cxgbi/Makefile b/drivers/scsi/cxgbi/Makefile index f78c9cc460a2..abfd38a26fec 100644 --- a/drivers/scsi/cxgbi/Makefile +++ b/drivers/scsi/cxgbi/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only ccflags-y += -I $(srctree)/drivers/net/ethernet/chelsio/libcxgb obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libcxgbi.o cxgb3i/ diff --git a/drivers/scsi/cxgbi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild index 663c52e05d81..8d8a43f5ea80 100644 --- a/drivers/scsi/cxgbi/cxgb3i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3 ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/libcxgb diff --git a/drivers/scsi/cxgbi/cxgb3i/Kconfig b/drivers/scsi/cxgbi/cxgb3i/Kconfig index f68c871b16ca..3e4b644249cb 100644 --- a/drivers/scsi/cxgbi/cxgb3i/Kconfig +++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_CXGB3_ISCSI tristate "Chelsio T3 iSCSI support" depends on PCI && INET && (IPV6 || IPV6=n) diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 75e1273a44b3..524cdbcd29aa 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -979,14 +979,17 @@ static int init_act_open(struct cxgbi_sock *csk) csk->atid = cxgb3_alloc_atid(t3dev, &t3_client, csk); if (csk->atid < 0) { pr_err("NO atid available.\n"); - goto rel_resource; + return -EINVAL; } cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); cxgbi_sock_get(csk); skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL); - if (!skb) - goto rel_resource; + if (!skb) { + cxgb3_free_atid(t3dev, csk->atid); + cxgbi_sock_put(csk); + return -ENOMEM; + } skb->sk = (struct sock *)csk; set_arp_failure_handler(skb, act_open_arp_failure); csk->snd_win = cxgb3i_snd_win; @@ -1007,11 +1010,6 @@ static int init_act_open(struct cxgbi_sock *csk) cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); send_act_open_req(csk, skb, csk->l2t); return 0; - -rel_resource: - if (skb) - __kfree_skb(skb); - return -EINVAL; } cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS] = { @@ -1245,8 +1243,12 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev) tformat.pgsz_order[i] = uinfo.pgsz_factor[i]; cxgbi_tagmask_check(tagmask, &tformat); - cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat, ppmax, - uinfo.llimit, uinfo.llimit, 0); + err = cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat, + (uinfo.ulimit - uinfo.llimit + 1), + uinfo.llimit, uinfo.llimit, 0, 0, 0); + if (err) + return err; + if (!(cdev->flags & CXGBI_FLAG_DDP_OFF)) { uinfo.tagmask = tagmask; uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT); @@ -1320,7 +1322,7 @@ static void cxgb3i_dev_open(struct t3cdev *t3dev) err = cxgb3i_ddp_init(cdev); if (err) { - pr_info("0x%p ddp init failed\n", cdev); + pr_info("0x%p ddp init failed %d\n", cdev, err); goto err_out; } diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild index 38e03c280417..fd3e0c964de6 100644 --- a/drivers/scsi/cxgbi/cxgb4i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4 ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/libcxgb diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig b/drivers/scsi/cxgbi/cxgb4i/Kconfig index f36b76e8e12c..d1f1baba3285 100644 --- a/drivers/scsi/cxgbi/cxgb4i/Kconfig +++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_CXGB4_ISCSI tristate "Chelsio T4 iSCSI support" depends on PCI && INET && (IPV6 || IPV6=n) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index d44914e5e415..da50e87921bc 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(dbg_level, "Debug flag (default=0)"); #define CXGB4I_DEFAULT_10G_RCV_WIN (256 * 1024) static int cxgb4i_rcv_win = -1; module_param(cxgb4i_rcv_win, int, 0644); -MODULE_PARM_DESC(cxgb4i_rcv_win, "TCP reveive window in bytes"); +MODULE_PARM_DESC(cxgb4i_rcv_win, "TCP receive window in bytes"); #define CXGB4I_DEFAULT_10G_SND_WIN (128 * 1024) static int cxgb4i_snd_win = -1; @@ -1665,8 +1665,12 @@ static u8 get_iscsi_dcb_priority(struct net_device *ndev) return 0; if (caps & DCB_CAP_DCBX_VER_IEEE) { - iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; + iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM; rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); + if (!rv) { + iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; + rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); + } } else if (caps & DCB_CAP_DCBX_VER_CEE) { iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM; rv = dcb_getapp(ndev, &iscsi_dcb_app); @@ -2070,7 +2074,7 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) struct net_device *ndev = cdev->ports[0]; struct cxgbi_tag_format tformat; unsigned int ppmax; - int i; + int i, err; if (!lldi->vr->iscsi.size) { pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name); @@ -2086,8 +2090,17 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) & 0xF; cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat); - cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, ppmax, - lldi->iscsi_llimit, lldi->vr->iscsi.start, 2); + pr_info("iscsi_edram.start 0x%x iscsi_edram.size 0x%x", + lldi->vr->ppod_edram.start, lldi->vr->ppod_edram.size); + + err = cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, + lldi->vr->iscsi.size, lldi->iscsi_llimit, + lldi->vr->iscsi.start, 2, + lldi->vr->ppod_edram.start, + lldi->vr->ppod_edram.size); + + if (err < 0) + return err; cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; @@ -2141,7 +2154,7 @@ static void *t4_uld_add(const struct cxgb4_lld_info *lldi) rc = cxgb4i_ddp_init(cdev); if (rc) { - pr_info("t4 0x%p ddp init failed.\n", cdev); + pr_info("t4 0x%p ddp init failed %d.\n", cdev, rc); goto err_out; } rc = cxgb4i_ofld_init(cdev); @@ -2251,7 +2264,8 @@ cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val, u8 priority; if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { - if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY) + if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) && + (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)) return NOTIFY_DONE; priority = iscsi_app->app.priority; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 006372b3fba2..3e17af8aedeb 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -282,7 +282,6 @@ struct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *ndev, } EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev_rcu); -#if IS_ENABLED(CONFIG_IPV6) static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, int *port) { @@ -315,7 +314,6 @@ static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, ndev, ndev->name); return NULL; } -#endif void cxgbi_hbas_remove(struct cxgbi_device *cdev) { @@ -641,6 +639,10 @@ cxgbi_check_route(struct sockaddr *dst_addr, int ifindex) if (ndev->flags & IFF_LOOPBACK) { ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); + if (!ndev) { + err = -ENETUNREACH; + goto rel_neigh; + } mtu = ndev->mtu; pr_info("rt dev %s, loopback -> %s, mtu %u.\n", n->dev->name, ndev->name, mtu); @@ -653,6 +655,8 @@ cxgbi_check_route(struct sockaddr *dst_addr, int ifindex) } cdev = cxgbi_device_find_by_netdev(ndev, &port); + if (!cdev) + cdev = cxgbi_device_find_by_mac(ndev, &port); if (!cdev) { pr_info("dst %pI4, %s, NOT cxgbi device.\n", &daddr->sin_addr.s_addr, ndev->name); @@ -1281,14 +1285,15 @@ EXPORT_SYMBOL_GPL(cxgbi_ddp_set_one_ppod); static unsigned char padding[4]; -void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, - struct cxgbi_tag_format *tformat, unsigned int ppmax, - unsigned int llimit, unsigned int start, - unsigned int rsvd_factor) +int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, + struct cxgbi_tag_format *tformat, + unsigned int iscsi_size, unsigned int llimit, + unsigned int start, unsigned int rsvd_factor, + unsigned int edram_start, unsigned int edram_size) { int err = cxgbi_ppm_init(ppm_pp, cdev->ports[0], cdev->pdev, - cdev->lldev, tformat, ppmax, llimit, start, - rsvd_factor); + cdev->lldev, tformat, iscsi_size, llimit, start, + rsvd_factor, edram_start, edram_size); if (err >= 0) { struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp); @@ -1300,6 +1305,8 @@ void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, } else { cdev->flags |= CXGBI_FLAG_DDP_OFF; } + + return err; } EXPORT_SYMBOL_GPL(cxgbi_ddp_ppm_setup); @@ -2310,7 +2317,6 @@ int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, { struct cxgbi_endpoint *cep = ep->dd_data; struct cxgbi_sock *csk; - int len; log_debug(1 << CXGBI_DBG_ISCSI, "cls_conn 0x%p, param %d.\n", ep, param); @@ -2328,9 +2334,9 @@ int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, return iscsi_conn_get_addr_param((struct sockaddr_storage *) &csk->daddr, param, buf); default: - return -ENOSYS; + break; } - return len; + return -ENOSYS; } EXPORT_SYMBOL_GPL(cxgbi_get_ep_param); @@ -2563,13 +2569,9 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, pr_info("shost 0x%p, priv NULL.\n", shost); goto err_out; } - - rtnl_lock(); - if (!vlan_uses_dev(hba->ndev)) - ifindex = hba->ndev->ifindex; - rtnl_unlock(); } +check_route: if (dst_addr->sa_family == AF_INET) { csk = cxgbi_check_route(dst_addr, ifindex); #if IS_ENABLED(CONFIG_IPV6) @@ -2590,6 +2592,13 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, if (!hba) hba = csk->cdev->hbas[csk->port_id]; else if (hba != csk->cdev->hbas[csk->port_id]) { + if (ifindex != hba->ndev->ifindex) { + cxgbi_sock_put(csk); + cxgbi_sock_closed(csk); + ifindex = hba->ndev->ifindex; + goto check_route; + } + pr_info("Could not connect through requested host %u" "hba 0x%p != 0x%p (%u).\n", shost->host_no, hba, diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 1917ff57651d..84b96af52655 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -617,8 +617,9 @@ void cxgbi_ddp_page_size_factor(int *); void cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *, struct cxgbi_task_tag_info *, struct scatterlist **sg_pp, unsigned int *sg_off); -void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *, - struct cxgbi_tag_format *, unsigned int ppmax, - unsigned int llimit, unsigned int start, - unsigned int rsvd_factor); +int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, + struct cxgbi_tag_format *tformat, + unsigned int iscsi_size, unsigned int llimit, + unsigned int start, unsigned int rsvd_factor, + unsigned int edram_start, unsigned int edram_size); #endif /*__LIBCXGBI_H__*/ diff --git a/drivers/scsi/cxlflash/Kconfig b/drivers/scsi/cxlflash/Kconfig index f1b17e3efb3f..5533bdcb0458 100644 --- a/drivers/scsi/cxlflash/Kconfig +++ b/drivers/scsi/cxlflash/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # IBM CXL-attached Flash Accelerator SCSI Driver # diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile index 283377d8f6fb..fd2f0dd9daf9 100644 --- a/drivers/scsi/cxlflash/Makefile +++ b/drivers/scsi/cxlflash/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_CXLFLASH) += cxlflash.o cxlflash-y += main.o superpipe.o lunmgt.o vlun.o cxlflash-$(CONFIG_CXL) += cxl_hw.o diff --git a/drivers/scsi/cxlflash/backend.h b/drivers/scsi/cxlflash/backend.h index 55638d19c2fd..181e0445ed42 100644 --- a/drivers/scsi/cxlflash/backend.h +++ b/drivers/scsi/cxlflash/backend.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2018 IBM Corporation - * - * 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. */ #ifndef _CXLFLASH_BACKEND_H diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 4d90106fcb37..de6229e27b48 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #ifndef _CXLFLASH_COMMON_H diff --git a/drivers/scsi/cxlflash/cxl_hw.c b/drivers/scsi/cxlflash/cxl_hw.c index b42da88386bd..b814130f3f5c 100644 --- a/drivers/scsi/cxlflash/cxl_hw.c +++ b/drivers/scsi/cxlflash/cxl_hw.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2018 IBM Corporation - * - * 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. */ #include <misc/cxl.h> diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index edea1255fdab..e0e15b44a2e6 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #include <asm/unaligned.h> diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 7096810fd222..b1f4724efde2 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #include <linux/delay.h> diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index a39be94d110c..0bfb98effce0 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #ifndef _CXLFLASH_MAIN_H diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index 37b8dc60f5f6..96740c6fcd92 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2018 IBM Corporation - * - * 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. */ #include <linux/file.h> diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h index 9270d35c4620..fc6ad4f985de 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.h +++ b/drivers/scsi/cxlflash/ocxl_hw.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2018 IBM Corporation - * - * 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. */ #define OCXL_MAX_IRQS 4 /* Max interrupts per process */ diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 874abce35ab4..ab315c59505b 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #ifndef _SISLITE_H diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 1a94a469051e..593669ac3669 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #include <linux/delay.h> diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 35c3cbf83fb5..0e3b45964066 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #ifndef _CXLFLASH_SUPERPIPE_H diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 2c904bf16b65..f1406ac77b0d 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #include <linux/interrupt.h> diff --git a/drivers/scsi/cxlflash/vlun.h b/drivers/scsi/cxlflash/vlun.h index 27a63a0155ce..68e3ea52fe80 100644 --- a/drivers/scsi/cxlflash/vlun.h +++ b/drivers/scsi/cxlflash/vlun.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * CXL Flash Device Driver * @@ -5,11 +6,6 @@ * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) 2015 IBM Corporation - * - * 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. */ #ifndef _CXLFLASH_VLUN_H diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig index 0b331c9c0a8f..368eb94c2456 100644 --- a/drivers/scsi/device_handler/Kconfig +++ b/drivers/scsi/device_handler/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # SCSI Device Handler configuration # diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile index 09866c50fbb4..0a603aefd2bb 100644 --- a/drivers/scsi/device_handler/Makefile +++ b/drivers/scsi/device_handler/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # SCSI Device Handler # diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index d7ac498ba35a..f0066f8a1786 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Generic SCSI-3 ALUA SCSI Device Handler * * Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH. * All rights reserved. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * */ #include <linux/slab.h> #include <linux/delay.h> @@ -1174,10 +1160,8 @@ static int __init alua_init(void) int r; kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0); - if (!kaluad_wq) { - /* Temporary failure, bypass */ - return SCSI_DH_DEV_TEMP_BUSY; - } + if (!kaluad_wq) + return -ENOMEM; r = scsi_register_device_handler(&alua_dh); if (r != 0) { diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index bea8e13febb6..caa685cfe3d4 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Target driver for EMC CLARiiON AX/CX-series hardware. * Based on code from Lars Marowsky-Bree <lmb@suse.de> @@ -5,20 +6,6 @@ * * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2006 Mike Christie - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 80129b033855..8acd4bb9fefb 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be * upgraded. @@ -5,20 +6,6 @@ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2006 Mike Christie * Copyright (C) 2008 Hannes Reinecke <hare@suse.de> - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/slab.h> diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c index 8db1cc552932..6df60b31ecb0 100644 --- a/drivers/scsi/dmx3191d.c +++ b/drivers/scsi/dmx3191d.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* dmx3191d.c - driver for the Domex DMX3191D SCSI card. Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it> @@ -5,19 +6,6 @@ Based on the generic NCR5380 driver by Drew Eckhardt et al. - 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 program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/init.h> diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h index 16fc380b5512..bf0daeeb50a9 100644 --- a/drivers/scsi/dpt/dpti_i2o.h +++ b/drivers/scsi/dpt/dpti_i2o.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef _SCSI_I2O_H #define _SCSI_I2O_H @@ -5,16 +6,10 @@ * * (c) Copyright 1999, 2000 Red Hat Software * - * 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 header file defined the I2O APIs/structures for use by * the I2O kernel modules. - * */ #ifdef __KERNEL__ /* This file to be included by kernel only */ diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h index f60236721e0d..6bc33f4f020d 100644 --- a/drivers/scsi/dpt/dpti_ioctl.h +++ b/drivers/scsi/dpt/dpti_ioctl.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** dpti_ioctl.h - description ------------------- @@ -10,10 +11,6 @@ /*************************************************************************** * * - * 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. * * * ***************************************************************************/ diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index abdc34affdf6..abc74fd474dc 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** dpti.c - description ------------------- @@ -13,10 +14,6 @@ /*************************************************************************** * * - * 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. * * * ***************************************************************************/ /*************************************************************************** @@ -835,8 +832,8 @@ static void adpt_i2o_sys_shutdown(void) adpt_hba *pHba, *pNext; struct adpt_i2o_post_wait_data *p1, *old; - printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n"); - printk(KERN_INFO" This could take a few minutes if there are many devices attached\n"); + printk(KERN_INFO "Shutting down Adaptec I2O controllers.\n"); + printk(KERN_INFO " This could take a few minutes if there are many devices attached\n"); /* Delete all IOPs from the controller chain */ /* They should have already been released by the * scsi-core @@ -859,7 +856,7 @@ static void adpt_i2o_sys_shutdown(void) // spin_unlock_irqrestore(&adpt_post_wait_lock, flags); adpt_post_wait_queue = NULL; - printk(KERN_INFO "Adaptec I2O controllers down.\n"); + printk(KERN_INFO "Adaptec I2O controllers down.\n"); } static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) @@ -3390,7 +3387,7 @@ static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ } - return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ + return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ } @@ -3463,8 +3460,8 @@ static int adpt_i2o_enable_hba(adpt_hba* pHba) static int adpt_i2o_systab_send(adpt_hba* pHba) { - u32 msg[12]; - int ret; + u32 msg[12]; + int ret; msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index dfc8d2eaa09e..42b1e28b5884 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** dpti.h - description ------------------- @@ -10,10 +11,6 @@ /*************************************************************************** * * - * 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. * * * ***************************************************************************/ diff --git a/drivers/scsi/esas2r/Kconfig b/drivers/scsi/esas2r/Kconfig index 78fdbfd9b4b7..19f6d3029658 100644 --- a/drivers/scsi/esas2r/Kconfig +++ b/drivers/scsi/esas2r/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_ESAS2R tristate "ATTO Technology's ExpressSAS RAID adapter driver" depends on PCI && SCSI diff --git a/drivers/scsi/esas2r/Makefile b/drivers/scsi/esas2r/Makefile index c77160b8c8bd..279d9cb3ca69 100644 --- a/drivers/scsi/esas2r/Makefile +++ b/drivers/scsi/esas2r/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SCSI_ESAS2R) += esas2r.o esas2r-objs := esas2r_log.o esas2r_disc.o esas2r_flash.o esas2r_init.o \ diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 465df475f753..bb88995a12c7 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* esp_scsi.c: ESP SCSI driver. * * Copyright (C) 2007 David S. Miller (davem@davemloft.net) @@ -370,6 +371,7 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); struct scatterlist *sg = scsi_sglist(cmd); int total = 0, i; + struct scatterlist *s; if (cmd->sc_data_direction == DMA_NONE) return; @@ -380,16 +382,18 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) * a dma address, so perform an identity mapping. */ spriv->num_sg = scsi_sg_count(cmd); - for (i = 0; i < spriv->num_sg; i++) { - sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]); - total += sg_dma_len(&sg[i]); + + scsi_for_each_sg(cmd, s, spriv->num_sg, i) { + s->dma_address = (uintptr_t)sg_virt(s); + total += sg_dma_len(s); } } else { spriv->num_sg = scsi_dma_map(cmd); - for (i = 0; i < spriv->num_sg; i++) - total += sg_dma_len(&sg[i]); + scsi_for_each_sg(cmd, s, spriv->num_sg, i) + total += sg_dma_len(s); } spriv->cur_residue = sg_dma_len(sg); + spriv->prv_sg = NULL; spriv->cur_sg = sg; spriv->tot_residue = total; } @@ -443,7 +447,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, p->tot_residue = 0; } if (!p->cur_residue && p->tot_residue) { - p->cur_sg++; + p->prv_sg = p->cur_sg; + p->cur_sg = sg_next(p->cur_sg); p->cur_residue = sg_dma_len(p->cur_sg); } } @@ -464,6 +469,7 @@ static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) return; } ent->saved_cur_residue = spriv->cur_residue; + ent->saved_prv_sg = spriv->prv_sg; ent->saved_cur_sg = spriv->cur_sg; ent->saved_tot_residue = spriv->tot_residue; } @@ -478,6 +484,7 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) return; } spriv->cur_residue = ent->saved_cur_residue; + spriv->prv_sg = ent->saved_prv_sg; spriv->cur_sg = ent->saved_cur_sg; spriv->tot_residue = ent->saved_tot_residue; } @@ -1031,7 +1038,7 @@ static int esp_check_spur_intr(struct esp *esp) static void esp_schedule_reset(struct esp *esp) { - esp_log_reset("esp_schedule_reset() from %pf\n", + esp_log_reset("esp_schedule_reset() from %ps\n", __builtin_return_address(0)); esp->flags |= ESP_FLAG_RESETTING; esp_event(esp, ESP_EVENT_RESET); @@ -1646,7 +1653,7 @@ static int esp_msgin_process(struct esp *esp) spriv = ESP_CMD_PRIV(ent->cmd); if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) { - spriv->cur_sg--; + spriv->cur_sg = spriv->prv_sg; spriv->cur_residue = 1; } else spriv->cur_residue++; diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index aa87a6b72dcc..91b32f2a1a1b 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -251,6 +251,7 @@ struct esp_cmd_priv { int num_sg; int cur_residue; + struct scatterlist *prv_sg; struct scatterlist *cur_sg; int tot_residue; }; @@ -273,6 +274,7 @@ struct esp_cmd_entry { struct scsi_cmnd *cmd; unsigned int saved_cur_residue; + struct scatterlist *saved_prv_sg; struct scatterlist *saved_cur_sg; unsigned int saved_tot_residue; diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile index aed0f5db3668..1183e80a09e7 100644 --- a/drivers/scsi/fcoe/Makefile +++ b/drivers/scsi/fcoe/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_FCOE) += fcoe.o obj-$(CONFIG_LIBFCOE) += libfcoe.o diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 8ba8862d3292..00dd47bcbb1e 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 6aa4820f6cc0..520c53512925 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright(c) 2009 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 7dc4ffa24430..590ec8009f52 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index c3dcbdc3aa64..2cb7a8c93a15 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2011 - 2012 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 29fe3426f9f2..ba4603d76284 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c new file mode 100644 index 000000000000..b5e66971b6d9 --- /dev/null +++ b/drivers/scsi/fdomain.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters + * Copyright 2019 Ondrej Zary + * + * Original driver by + * Rickard E. Faith, faith@cs.unc.edu + * + * 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 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 ? + * + * 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. + * + * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for + * your board. + * + * 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. + * + * 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. + * + * + * 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. + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/workqueue.h> +#include <scsi/scsicam.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include "fdomain.h" + +/* + * 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. + */ +#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ +#define PARITY_MASK ACTL_PAREN /* Parity enabled, 0 = disabled */ + +enum chip_type { + unknown = 0x00, + tmc1800 = 0x01, + tmc18c50 = 0x02, + tmc18c30 = 0x03, +}; + +struct fdomain { + int base; + struct scsi_cmnd *cur_cmd; + enum chip_type chip; + struct work_struct work; +}; + +static inline void fdomain_make_bus_idle(struct fdomain *fd) +{ + outb(0, fd->base + REG_BCTL); + outb(0, fd->base + REG_MCTL); + if (fd->chip == tmc18c50 || fd->chip == tmc18c30) + /* Clear forced intr. */ + outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK, + fd->base + REG_ACTL); + else + outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL); +} + +static enum chip_type fdomain_identify(int port) +{ + u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8; + + switch (id) { + case 0x6127: + return tmc1800; + case 0x60e9: /* 18c50 or 18c30 */ + break; + default: + return unknown; + } + + /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */ + outb(CFG2_32BIT, port + REG_CFG2); + if ((inb(port + REG_CFG2) & CFG2_32BIT)) { + outb(0, port + REG_CFG2); + if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0) + return tmc18c30; + } + /* If that failed, we are an 18c50. */ + return tmc18c50; +} + +static int fdomain_test_loopback(int base) +{ + int i; + + for (i = 0; i < 255; i++) { + outb(i, base + REG_LOOPBACK); + if (inb(base + REG_LOOPBACK) != i) + return 1; + } + + return 0; +} + +static void fdomain_reset(int base) +{ + outb(1, base + REG_BCTL); + mdelay(20); + outb(0, base + REG_BCTL); + mdelay(1150); + outb(0, base + REG_MCTL); + outb(PARITY_MASK, base + REG_ACTL); +} + +static int fdomain_select(struct Scsi_Host *sh, int target) +{ + int status; + unsigned long timeout; + struct fdomain *fd = shost_priv(sh); + + outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL); + outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK); + + /* Stop arbitration and enable parity */ + outb(PARITY_MASK, fd->base + REG_ACTL); + + timeout = 350; /* 350 msec */ + + do { + status = inb(fd->base + REG_BSTAT); + if (status & BSTAT_BSY) { + /* Enable SCSI Bus */ + /* (on error, should make bus idle with 0) */ + outb(BCTL_BUSEN, fd->base + REG_BCTL); + return 0; + } + mdelay(1); + } while (--timeout); + fdomain_make_bus_idle(fd); + return 1; +} + +static void fdomain_finish_cmd(struct fdomain *fd, int result) +{ + outb(0, fd->base + REG_ICTL); + fdomain_make_bus_idle(fd); + fd->cur_cmd->result = result; + fd->cur_cmd->scsi_done(fd->cur_cmd); + fd->cur_cmd = NULL; +} + +static void fdomain_read_data(struct scsi_cmnd *cmd) +{ + struct fdomain *fd = shost_priv(cmd->device->host); + unsigned char *virt, *ptr; + size_t offset, len; + + while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) { + offset = scsi_bufflen(cmd) - scsi_get_resid(cmd); + virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd), + &offset, &len); + ptr = virt + offset; + if (len & 1) + *ptr++ = inb(fd->base + REG_FIFO); + if (len > 1) + insw(fd->base + REG_FIFO, ptr, len >> 1); + scsi_set_resid(cmd, scsi_get_resid(cmd) - len); + scsi_kunmap_atomic_sg(virt); + } +} + +static void fdomain_write_data(struct scsi_cmnd *cmd) +{ + struct fdomain *fd = shost_priv(cmd->device->host); + /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */ + int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000; + unsigned char *virt, *ptr; + size_t offset, len; + + while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) { + offset = scsi_bufflen(cmd) - scsi_get_resid(cmd); + if (len + offset > scsi_bufflen(cmd)) { + len = scsi_bufflen(cmd) - offset; + if (len == 0) + break; + } + virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd), + &offset, &len); + ptr = virt + offset; + if (len & 1) + outb(*ptr++, fd->base + REG_FIFO); + if (len > 1) + outsw(fd->base + REG_FIFO, ptr, len >> 1); + scsi_set_resid(cmd, scsi_get_resid(cmd) - len); + scsi_kunmap_atomic_sg(virt); + } +} + +static void fdomain_work(struct work_struct *work) +{ + struct fdomain *fd = container_of(work, struct fdomain, work); + struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host, + hostdata); + struct scsi_cmnd *cmd = fd->cur_cmd; + unsigned long flags; + int status; + int done = 0; + + spin_lock_irqsave(sh->host_lock, flags); + + if (cmd->SCp.phase & in_arbitration) { + status = inb(fd->base + REG_ASTAT); + if (!(status & ASTAT_ARB)) { + fdomain_finish_cmd(fd, DID_BUS_BUSY << 16); + goto out; + } + cmd->SCp.phase = in_selection; + + outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL); + outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL); + outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)), + fd->base + REG_SCSI_DATA_NOACK); + /* Stop arbitration and enable parity */ + outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); + goto out; + } else if (cmd->SCp.phase & in_selection) { + status = inb(fd->base + REG_BSTAT); + if (!(status & BSTAT_BSY)) { + /* Try again, for slow devices */ + if (fdomain_select(cmd->device->host, scmd_id(cmd))) { + fdomain_finish_cmd(fd, DID_NO_CONNECT << 16); + goto out; + } + /* Stop arbitration and enable parity */ + outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); + } + cmd->SCp.phase = in_other; + outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL); + outb(BCTL_BUSEN, fd->base + REG_BCTL); + goto out; + } + + /* cur_cmd->SCp.phase == in_other: this is the body of the routine */ + status = inb(fd->base + REG_BSTAT); + + if (status & BSTAT_REQ) { + switch (status & 0x0e) { + case BSTAT_CMD: /* COMMAND OUT */ + outb(cmd->cmnd[cmd->SCp.sent_command++], + fd->base + REG_SCSI_DATA); + break; + case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */ + if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { + cmd->SCp.have_data_in = -1; + outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN | + PARITY_MASK, fd->base + REG_ACTL); + } + break; + case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */ + if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { + cmd->SCp.have_data_in = 1; + outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK, + fd->base + REG_ACTL); + } + break; + case BSTAT_CMD | BSTAT_IO: /* STATUS IN */ + cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA); + break; + case BSTAT_MSG | BSTAT_CMD: /* MESSAGE OUT */ + outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA); + break; + case BSTAT_MSG | BSTAT_IO | BSTAT_CMD: /* MESSAGE IN */ + cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA); + if (!cmd->SCp.Message) + ++done; + break; + } + } + + if (fd->chip == tmc1800 && !cmd->SCp.have_data_in && + cmd->SCp.sent_command >= cmd->cmd_len) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + cmd->SCp.have_data_in = -1; + outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN | + PARITY_MASK, fd->base + REG_ACTL); + } else { + cmd->SCp.have_data_in = 1; + outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK, + fd->base + REG_ACTL); + } + } + + if (cmd->SCp.have_data_in == -1) /* DATA OUT */ + fdomain_write_data(cmd); + + if (cmd->SCp.have_data_in == 1) /* DATA IN */ + fdomain_read_data(cmd); + + if (done) { + fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) | + ((cmd->SCp.Message & 0xff) << 8) | + (DID_OK << 16)); + } else { + if (cmd->SCp.phase & disconnect) { + outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT, + fd->base + REG_ICTL); + outb(0, fd->base + REG_BCTL); + } else + outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, + fd->base + REG_ICTL); + } +out: + spin_unlock_irqrestore(sh->host_lock, flags); +} + +static irqreturn_t fdomain_irq(int irq, void *dev_id) +{ + struct fdomain *fd = dev_id; + + /* Is it our IRQ? */ + if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0) + return IRQ_NONE; + + outb(0, fd->base + REG_ICTL); + + /* We usually have one spurious interrupt after each command. */ + if (!fd->cur_cmd) /* Spurious interrupt */ + return IRQ_NONE; + + schedule_work(&fd->work); + + return IRQ_HANDLED; +} + +static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +{ + struct fdomain *fd = shost_priv(cmd->device->host); + unsigned long flags; + + cmd->SCp.Status = 0; + cmd->SCp.Message = 0; + cmd->SCp.have_data_in = 0; + cmd->SCp.sent_command = 0; + cmd->SCp.phase = in_arbitration; + scsi_set_resid(cmd, scsi_bufflen(cmd)); + + spin_lock_irqsave(sh->host_lock, flags); + + fd->cur_cmd = cmd; + + fdomain_make_bus_idle(fd); + + /* Start arbitration */ + outb(0, fd->base + REG_ICTL); + outb(0, fd->base + REG_BCTL); /* Disable data drivers */ + /* Set our id bit */ + outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK); + outb(ICTL_ARB, fd->base + REG_ICTL); + /* Start arbitration */ + outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); + + spin_unlock_irqrestore(sh->host_lock, flags); + + return 0; +} + +static int fdomain_abort(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *sh = cmd->device->host; + struct fdomain *fd = shost_priv(sh); + unsigned long flags; + + if (!fd->cur_cmd) + return FAILED; + + spin_lock_irqsave(sh->host_lock, flags); + + fdomain_make_bus_idle(fd); + fd->cur_cmd->SCp.phase |= aborted; + fd->cur_cmd->result = DID_ABORT << 16; + + /* Aborts are not done well. . . */ + fdomain_finish_cmd(fd, DID_ABORT << 16); + spin_unlock_irqrestore(sh->host_lock, flags); + return SUCCESS; +} + +static int fdomain_host_reset(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *sh = cmd->device->host; + struct fdomain *fd = shost_priv(sh); + unsigned long flags; + + spin_lock_irqsave(sh->host_lock, flags); + fdomain_reset(fd->base); + spin_unlock_irqrestore(sh->host_lock, flags); + return SUCCESS; +} + +static int fdomain_biosparam(struct scsi_device *sdev, + struct block_device *bdev, sector_t capacity, + int geom[]) +{ + unsigned char *p = scsi_bios_ptable(bdev); + + if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ + && p[4]) { /* Partition type */ + geom[0] = p[5] + 1; /* heads */ + geom[1] = p[6] & 0x3f; /* sectors */ + } else { + if (capacity >= 0x7e0000) { + geom[0] = 255; /* heads */ + geom[1] = 63; /* sectors */ + } else if (capacity >= 0x200000) { + geom[0] = 128; /* heads */ + geom[1] = 63; /* sectors */ + } else { + geom[0] = 64; /* heads */ + geom[1] = 32; /* sectors */ + } + } + geom[2] = sector_div(capacity, geom[0] * geom[1]); + kfree(p); + + return 0; +} + +static struct scsi_host_template fdomain_template = { + .module = THIS_MODULE, + .name = "Future Domain TMC-16x0", + .proc_name = "fdomain", + .queuecommand = fdomain_queue, + .eh_abort_handler = fdomain_abort, + .eh_host_reset_handler = fdomain_host_reset, + .bios_param = fdomain_biosparam, + .can_queue = 1, + .this_id = 7, + .sg_tablesize = 64, + .dma_boundary = PAGE_SIZE - 1, +}; + +struct Scsi_Host *fdomain_create(int base, int irq, int this_id, + struct device *dev) +{ + struct Scsi_Host *sh; + struct fdomain *fd; + enum chip_type chip; + static const char * const chip_names[] = { + "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30" + }; + unsigned long irq_flags = 0; + + chip = fdomain_identify(base); + if (!chip) + return NULL; + + fdomain_reset(base); + + if (fdomain_test_loopback(base)) + return NULL; + + if (!irq) { + dev_err(dev, "card has no IRQ assigned"); + return NULL; + } + + sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain)); + if (!sh) + return NULL; + + if (this_id) + sh->this_id = this_id & 0x07; + + sh->irq = irq; + sh->io_port = base; + sh->n_io_port = FDOMAIN_REGION_SIZE; + + fd = shost_priv(sh); + fd->base = base; + fd->chip = chip; + INIT_WORK(&fd->work, fdomain_work); + + if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia")) + irq_flags = IRQF_SHARED; + + if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd)) + goto fail_put; + + shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n", + dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip], + base, irq, sh->this_id); + + if (scsi_add_host(sh, dev)) + goto fail_free_irq; + + scsi_scan_host(sh); + + return sh; + +fail_free_irq: + free_irq(irq, fd); +fail_put: + scsi_host_put(sh); + return NULL; +} +EXPORT_SYMBOL_GPL(fdomain_create); + +int fdomain_destroy(struct Scsi_Host *sh) +{ + struct fdomain *fd = shost_priv(sh); + + cancel_work_sync(&fd->work); + scsi_remove_host(sh); + if (sh->irq) + free_irq(sh->irq, fd); + scsi_host_put(sh); + return 0; +} +EXPORT_SYMBOL_GPL(fdomain_destroy); + +#ifdef CONFIG_PM_SLEEP +static int fdomain_resume(struct device *dev) +{ + struct fdomain *fd = shost_priv(dev_get_drvdata(dev)); + + fdomain_reset(fd->base); + return 0; +} + +static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume); +#endif /* CONFIG_PM_SLEEP */ + +MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); +MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h new file mode 100644 index 000000000000..6f63fc6b0d12 --- /dev/null +++ b/drivers/scsi/fdomain.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define FDOMAIN_REGION_SIZE 0x10 +#define FDOMAIN_BIOS_SIZE 0x2000 + +enum { + in_arbitration = 0x02, + in_selection = 0x04, + in_other = 0x08, + disconnect = 0x10, + aborted = 0x20, + sent_ident = 0x40, +}; + +/* (@) = not present on TMC1800, (#) = not present on TMC1800 and TMC18C50 */ +#define REG_SCSI_DATA 0 /* R/W: SCSI Data (with ACK) */ +#define REG_BSTAT 1 /* R: SCSI Bus Status */ +#define BSTAT_BSY BIT(0) /* Busy */ +#define BSTAT_MSG BIT(1) /* Message */ +#define BSTAT_IO BIT(2) /* Input/Output */ +#define BSTAT_CMD BIT(3) /* Command/Data */ +#define BSTAT_REQ BIT(4) /* Request and Not Ack */ +#define BSTAT_SEL BIT(5) /* Select */ +#define BSTAT_ACK BIT(6) /* Acknowledge and Request */ +#define BSTAT_ATN BIT(7) /* Attention */ +#define REG_BCTL 1 /* W: SCSI Bus Control */ +#define BCTL_RST BIT(0) /* Bus Reset */ +#define BCTL_SEL BIT(1) /* Select */ +#define BCTL_BSY BIT(2) /* Busy */ +#define BCTL_ATN BIT(3) /* Attention */ +#define BCTL_IO BIT(4) /* Input/Output */ +#define BCTL_CMD BIT(5) /* Command/Data */ +#define BCTL_MSG BIT(6) /* Message */ +#define BCTL_BUSEN BIT(7) /* Enable bus drivers */ +#define REG_ASTAT 2 /* R: Adapter Status 1 */ +#define ASTAT_IRQ BIT(0) /* Interrupt active */ +#define ASTAT_ARB BIT(1) /* Arbitration complete */ +#define ASTAT_PARERR BIT(2) /* Parity error */ +#define ASTAT_RST BIT(3) /* SCSI reset occurred */ +#define ASTAT_FIFODIR BIT(4) /* FIFO direction */ +#define ASTAT_FIFOEN BIT(5) /* FIFO enabled */ +#define ASTAT_PAREN BIT(6) /* Parity enabled */ +#define ASTAT_BUSEN BIT(7) /* Bus drivers enabled */ +#define REG_ICTL 2 /* W: Interrupt Control */ +#define ICTL_FIFO_MASK 0x0f /* FIFO threshold, 1/16 FIFO size */ +#define ICTL_FIFO BIT(4) /* Int. on FIFO count */ +#define ICTL_ARB BIT(5) /* Int. on Arbitration complete */ +#define ICTL_SEL BIT(6) /* Int. on SCSI Select */ +#define ICTL_REQ BIT(7) /* Int. on SCSI Request */ +#define REG_FSTAT 3 /* R: Adapter Status 2 (FIFO) - (@) */ +#define FSTAT_ONOTEMPTY BIT(0) /* Output FIFO not empty */ +#define FSTAT_INOTEMPTY BIT(1) /* Input FIFO not empty */ +#define FSTAT_NOTEMPTY BIT(2) /* Main FIFO not empty */ +#define FSTAT_NOTFULL BIT(3) /* Main FIFO not full */ +#define REG_MCTL 3 /* W: SCSI Data Mode Control */ +#define MCTL_ACK_MASK 0x0f /* Acknowledge period */ +#define MCTL_ACTDEASS BIT(4) /* Active deassert of REQ and ACK */ +#define MCTL_TARGET BIT(5) /* Enable target mode */ +#define MCTL_FASTSYNC BIT(6) /* Enable Fast Synchronous */ +#define MCTL_SYNC BIT(7) /* Enable Synchronous */ +#define REG_INTCOND 4 /* R: Interrupt Condition - (@) */ +#define IRQ_FIFO BIT(1) /* FIFO interrupt */ +#define IRQ_REQ BIT(2) /* SCSI Request interrupt */ +#define IRQ_SEL BIT(3) /* SCSI Select interrupt */ +#define IRQ_ARB BIT(4) /* SCSI Arbitration interrupt */ +#define IRQ_RST BIT(5) /* SCSI Reset interrupt */ +#define IRQ_FORCED BIT(6) /* Forced interrupt */ +#define IRQ_TIMEOUT BIT(7) /* Bus timeout */ +#define REG_ACTL 4 /* W: Adapter Control 1 */ +#define ACTL_RESET BIT(0) /* Reset FIFO, parity, reset int. */ +#define ACTL_FIRQ BIT(1) /* Set Forced interrupt */ +#define ACTL_ARB BIT(2) /* Initiate Bus Arbitration */ +#define ACTL_PAREN BIT(3) /* Enable SCSI Parity */ +#define ACTL_IRQEN BIT(4) /* Enable interrupts */ +#define ACTL_CLRFIRQ BIT(5) /* Clear Forced interrupt */ +#define ACTL_FIFOWR BIT(6) /* FIFO Direction (1=write) */ +#define ACTL_FIFOEN BIT(7) /* Enable FIFO */ +#define REG_ID_LSB 5 /* R: ID Code (LSB) */ +#define REG_ACTL2 5 /* Adapter Control 2 - (@) */ +#define ACTL2_RAMOVRLY BIT(0) /* Enable RAM overlay */ +#define ACTL2_SLEEP BIT(7) /* Sleep mode */ +#define REG_ID_MSB 6 /* R: ID Code (MSB) */ +#define REG_LOOPBACK 7 /* R/W: Loopback */ +#define REG_SCSI_DATA_NOACK 8 /* R/W: SCSI Data (no ACK) */ +#define REG_ASTAT3 9 /* R: Adapter Status 3 */ +#define ASTAT3_ACTDEASS BIT(0) /* Active deassert enabled */ +#define ASTAT3_RAMOVRLY BIT(1) /* RAM overlay enabled */ +#define ASTAT3_TARGERR BIT(2) /* Target error */ +#define ASTAT3_IRQEN BIT(3) /* Interrupts enabled */ +#define ASTAT3_IRQMASK 0xf0 /* Enabled interrupts mask */ +#define REG_CFG1 10 /* R: Configuration Register 1 */ +#define CFG1_BUS BIT(0) /* 0 = ISA */ +#define CFG1_IRQ_MASK 0x0e /* IRQ jumpers */ +#define CFG1_IO_MASK 0x30 /* I/O base jumpers */ +#define CFG1_BIOS_MASK 0xc0 /* BIOS base jumpers */ +#define REG_CFG2 11 /* R/W: Configuration Register 2 (@) */ +#define CFG2_ROMDIS BIT(0) /* ROM disabled */ +#define CFG2_RAMDIS BIT(1) /* RAM disabled */ +#define CFG2_IRQEDGE BIT(2) /* Edge-triggered interrupts */ +#define CFG2_NOWS BIT(3) /* No wait states */ +#define CFG2_32BIT BIT(7) /* 32-bit mode */ +#define REG_FIFO 12 /* R/W: FIFO */ +#define REG_FIFO_COUNT 14 /* R: FIFO Data Count */ + +#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops fdomain_pm_ops; +#define FDOMAIN_PM_OPS (&fdomain_pm_ops) +#else +#define FDOMAIN_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +struct Scsi_Host *fdomain_create(int base, int irq, int this_id, + struct device *dev); +int fdomain_destroy(struct Scsi_Host *sh); diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c new file mode 100644 index 000000000000..28639adf8219 --- /dev/null +++ b/drivers/scsi/fdomain_isa.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/module.h> +#include <linux/io.h> +#include <linux/isa.h> +#include <scsi/scsi_host.h> +#include "fdomain.h" + +#define MAXBOARDS_PARAM 4 +static int io[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; +module_param_hw_array(io, int, ioport, NULL, 0); +MODULE_PARM_DESC(io, "base I/O address of controller (0x140, 0x150, 0x160, 0x170)"); + +static int irq[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; +module_param_hw_array(irq, int, irq, NULL, 0); +MODULE_PARM_DESC(irq, "IRQ of controller (0=auto [default])"); + +static int scsi_id[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; +module_param_hw_array(scsi_id, int, other, NULL, 0); +MODULE_PARM_DESC(scsi_id, "SCSI ID of controller (default = 7)"); + +static unsigned long addresses[] = { + 0xc8000, + 0xca000, + 0xce000, + 0xde000, +}; +#define ADDRESS_COUNT ARRAY_SIZE(addresses) + +static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; +#define PORT_COUNT ARRAY_SIZE(ports) + +static unsigned short irqs[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; + +/* 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. + * BIOS versions prior to 3.2 assigned SCSI ID 6 to SCSI adapter. + * + * 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.) + */ + +static struct signature { + const char *signature; + int offset; + int length; + int this_id; + int base_offset; +} signatures[] = { +/* 1 2 3 4 5 6 */ +/* 123456789012345678901234567890123456789012345678901234567890 */ +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 6, 0x1fcc }, +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 6, 0x1fcc }, +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 6, 0x1fa2 }, +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 6, 0x1fa2 }, +{ "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 6, 0x1fa3 }, +{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 6, 0 }, +{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 7, 0 }, +{ "IBM F1 P2 BIOS v1.0011/09/92", 5, 28, 7, 0x1ff3 }, +{ "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 7, 0 }, +{ "Future Domain Corp. V1.0008/18/93", 5, 33, 7, 0 }, +{ "Future Domain Corp. V2.0108/18/93", 5, 33, 7, 0 }, +{ "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 7, 0 }, +{ "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 7, 0 }, +{ "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 7, 0 }, +{ "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 7, 0 }, +}; +#define SIGNATURE_COUNT ARRAY_SIZE(signatures) + +static int fdomain_isa_match(struct device *dev, unsigned int ndev) +{ + struct Scsi_Host *sh; + int i, base = 0, irq = 0; + unsigned long bios_base = 0; + struct signature *sig = NULL; + void __iomem *p; + static struct signature *saved_sig; + int this_id = 7; + + if (ndev < ADDRESS_COUNT) { /* scan supported ISA BIOS addresses */ + p = ioremap(addresses[ndev], FDOMAIN_BIOS_SIZE); + if (!p) + return 0; + for (i = 0; i < SIGNATURE_COUNT; i++) + if (check_signature(p + signatures[i].offset, + signatures[i].signature, + signatures[i].length)) + break; + if (i == SIGNATURE_COUNT) /* no signature found */ + goto fail_unmap; + sig = &signatures[i]; + bios_base = addresses[ndev]; + /* read I/O base from BIOS area */ + if (sig->base_offset) + base = readb(p + sig->base_offset) + + (readb(p + sig->base_offset + 1) << 8); + iounmap(p); + if (base) + dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n", + bios_base, base); + else + dev_info(dev, "BIOS at 0x%lx\n", bios_base); + if (!base) { /* no I/O base in BIOS area */ + /* save BIOS signature for later use in port probing */ + saved_sig = sig; + return 0; + } + } else /* scan supported I/O ports */ + base = ports[ndev - ADDRESS_COUNT]; + + /* use saved BIOS signature if present */ + if (!sig && saved_sig) + sig = saved_sig; + + if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa")) + return 0; + + irq = irqs[(inb(base + REG_CFG1) & 0x0e) >> 1]; + + + if (sig) + this_id = sig->this_id; + + sh = fdomain_create(base, irq, this_id, dev); + if (!sh) { + release_region(base, FDOMAIN_REGION_SIZE); + return 0; + } + + dev_set_drvdata(dev, sh); + return 1; +fail_unmap: + iounmap(p); + return 0; +} + +static int fdomain_isa_param_match(struct device *dev, unsigned int ndev) +{ + struct Scsi_Host *sh; + int irq_ = irq[ndev]; + + if (!io[ndev]) + return 0; + + if (!request_region(io[ndev], FDOMAIN_REGION_SIZE, "fdomain_isa")) { + dev_err(dev, "base 0x%x already in use", io[ndev]); + return 0; + } + + if (irq_ <= 0) + irq_ = irqs[(inb(io[ndev] + REG_CFG1) & 0x0e) >> 1]; + + sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev); + if (!sh) { + dev_err(dev, "controller not found at base 0x%x", io[ndev]); + release_region(io[ndev], FDOMAIN_REGION_SIZE); + return 0; + } + + dev_set_drvdata(dev, sh); + return 1; +} + +static int fdomain_isa_remove(struct device *dev, unsigned int ndev) +{ + struct Scsi_Host *sh = dev_get_drvdata(dev); + int base = sh->io_port; + + fdomain_destroy(sh); + release_region(base, FDOMAIN_REGION_SIZE); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct isa_driver fdomain_isa_driver = { + .match = fdomain_isa_match, + .remove = fdomain_isa_remove, + .driver = { + .name = "fdomain_isa", + .pm = FDOMAIN_PM_OPS, + }, +}; + +static int __init fdomain_isa_init(void) +{ + int isa_probe_count = ADDRESS_COUNT + PORT_COUNT; + + if (io[0]) { /* use module parameters if present */ + fdomain_isa_driver.match = fdomain_isa_param_match; + isa_probe_count = MAXBOARDS_PARAM; + } + + return isa_register_driver(&fdomain_isa_driver, isa_probe_count); +} + +static void __exit fdomain_isa_exit(void) +{ + isa_unregister_driver(&fdomain_isa_driver); +} + +module_init(fdomain_isa_init); +module_exit(fdomain_isa_exit); + +MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); +MODULE_DESCRIPTION("Future Domain TMC-16x0 ISA SCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/fdomain_pci.c b/drivers/scsi/fdomain_pci.c new file mode 100644 index 000000000000..3e05ce7b89e5 --- /dev/null +++ b/drivers/scsi/fdomain_pci.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/module.h> +#include <linux/pci.h> +#include "fdomain.h" + +static int fdomain_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *d) +{ + int err; + struct Scsi_Host *sh; + + err = pci_enable_device(pdev); + if (err) + goto fail; + + err = pci_request_regions(pdev, "fdomain_pci"); + if (err) + goto disable_device; + + err = -ENODEV; + if (pci_resource_len(pdev, 0) == 0) + goto release_region; + + sh = fdomain_create(pci_resource_start(pdev, 0), pdev->irq, 7, + &pdev->dev); + if (!sh) + goto release_region; + + pci_set_drvdata(pdev, sh); + return 0; + +release_region: + pci_release_regions(pdev); +disable_device: + pci_disable_device(pdev); +fail: + return err; +} + +static void fdomain_pci_remove(struct pci_dev *pdev) +{ + struct Scsi_Host *sh = pci_get_drvdata(pdev); + + fdomain_destroy(sh); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id fdomain_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70) }, + {} +}; +MODULE_DEVICE_TABLE(pci, fdomain_pci_table); + +static struct pci_driver fdomain_pci_driver = { + .name = "fdomain_pci", + .id_table = fdomain_pci_table, + .probe = fdomain_pci_probe, + .remove = fdomain_pci_remove, + .driver.pm = FDOMAIN_PM_OPS, +}; + +module_pci_driver(fdomain_pci_driver); + +MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); +MODULE_DESCRIPTION("Future Domain TMC-3260 PCI SCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 9cdca0625498..2ab774e62e40 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic Generic NCR5380 driver * diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index e7f1dd4f3b66..fe03410268e6 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /************************************************************************ * Linux driver for * * ICP vortex GmbH: GDT PCI Disk Array Controllers * @@ -13,19 +14,6 @@ * Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> * * Johannes Dinner <johannes_dinner@adaptec.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 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. * * * * Linux kernel 2.6.x supported * * * @@ -3697,8 +3685,9 @@ static int ioc_general(void __user *arg, char *cmnd) rval = 0; out_free_buf: - dma_free_coherent(&ha->pdev->dev, gen.data_len + gen.sense_len, buf, - paddr); + if (buf) + dma_free_coherent(&ha->pdev->dev, gen.data_len + gen.sense_len, + buf, paddr); return rval; } diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index d2acd0d826e2..11df0eca0293 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only #include <linux/types.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig index 57183fce70fb..90a17452a50d 100644 --- a/drivers/scsi/hisi_sas/Kconfig +++ b/drivers/scsi/hisi_sas/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_HISI_SAS tristate "HiSilicon SAS" depends on HAS_IOMEM diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile index 24623f228510..742e732cd51d 100644 --- a/drivers/scsi/hisi_sas/Makefile +++ b/drivers/scsi/hisi_sas/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o hisi_sas_v2_hw.o obj-$(CONFIG_SCSI_HISI_SAS_PCI) += hisi_sas_v3_hw.o diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 9bfa9f12d81e..42a02cc47a60 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -1,12 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2015 Linaro Ltd. * Copyright (c) 2015 Hisilicon Limited. - * - * 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. - * */ #ifndef _HISI_SAS_H_ @@ -66,10 +61,6 @@ #define HISI_SAS_MAX_SMP_RESP_SZ 1028 #define HISI_SAS_MAX_STP_RESP_SZ 28 -#define DEV_IS_EXPANDER(type) \ - ((type == SAS_EDGE_EXPANDER_DEVICE) || \ - (type == SAS_FANOUT_EXPANDER_DEVICE)) - #define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1 #define HISI_SAS_SATA_PROTOCOL_PIO 0x2 #define HISI_SAS_SATA_PROTOCOL_DMA 0x4 @@ -170,6 +161,7 @@ struct hisi_sas_phy { u32 code_violation_err_count; enum sas_linkrate minimum_linkrate; enum sas_linkrate maximum_linkrate; + int enable; }; struct hisi_sas_port { @@ -483,12 +475,12 @@ struct hisi_sas_command_table_stp { u8 atapi_cdb[ATAPI_CDB_LEN]; }; -#define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE +#define HISI_SAS_SGE_PAGE_CNT (124) struct hisi_sas_sge_page { struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT]; } __aligned(16); -#define HISI_SAS_SGE_DIF_PAGE_CNT SG_CHUNK_SIZE +#define HISI_SAS_SGE_DIF_PAGE_CNT HISI_SAS_SGE_PAGE_CNT struct hisi_sas_sge_dif_page { struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT]; } __aligned(16); @@ -551,6 +543,8 @@ extern int hisi_sas_slave_configure(struct scsi_device *sdev); extern int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time); extern void hisi_sas_scan_start(struct Scsi_Host *shost); extern int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type); +extern void hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no, + int enable); extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy); extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 14bac4966c87..cb746cfc2fa8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1,16 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015 Linaro Ltd. * Copyright (c) 2015 Hisilicon Limited. - * - * 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. - * */ #include "hisi_sas.h" -#include "../libsas/sas_internal.h" #define DRV_NAME "hisi_sas" #define DEV_IS_GONE(dev) \ @@ -171,7 +165,7 @@ void hisi_sas_stop_phys(struct hisi_hba *hisi_hba) int phy_no; for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); } EXPORT_SYMBOL_GPL(hisi_sas_stop_phys); @@ -684,7 +678,7 @@ static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no) id->initiator_bits = SAS_PROTOCOL_ALL; id->target_bits = phy->identify.target_port_protocols; } else if (phy->phy_type & PORT_TYPE_SATA) { - /*Nothing*/ + /* Nothing */ } sas_phy->frame_rcvd_size = phy->frame_rcvd_size; @@ -755,7 +749,8 @@ static int hisi_sas_init_device(struct domain_device *device) * STP target port */ local_phy = sas_get_local_phy(device); - if (!scsi_is_sas_phy_local(local_phy)) { + if (!scsi_is_sas_phy_local(local_phy) && + !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { unsigned long deadline = ata_deadline(jiffies, 20000); struct sata_device *sata_dev = &device->sata_dev; struct ata_host *ata_host = sata_dev->ata_host; @@ -770,8 +765,7 @@ static int hisi_sas_init_device(struct domain_device *device) } sas_put_local_phy(local_phy); if (rc) { - dev_warn(dev, "SATA disk hardreset fail: 0x%x\n", - rc); + dev_warn(dev, "SATA disk hardreset fail: %d\n", rc); return rc; } @@ -809,7 +803,7 @@ static int hisi_sas_dev_found(struct domain_device *device) device->lldd_dev = sas_dev; hisi_hba->hw->setup_itct(hisi_hba, sas_dev); - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_no; u8 phy_num = parent_dev->ex_dev.num_phys; struct ex_phy *phy; @@ -976,6 +970,30 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no) timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0); } +/* Wrapper to ensure we track hisi_sas_phy.enable properly */ +void hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no, int enable) +{ + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *aphy = &phy->sas_phy; + struct sas_phy *sphy = aphy->phy; + unsigned long flags; + + spin_lock_irqsave(&phy->lock, flags); + + if (enable) { + /* We may have been enabled already; if so, don't touch */ + if (!phy->enable) + sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + hisi_hba->hw->phy_start(hisi_hba, phy_no); + } else { + sphy->negotiated_linkrate = SAS_PHY_DISABLED; + hisi_hba->hw->phy_disable(hisi_hba, phy_no); + } + phy->enable = enable; + spin_unlock_irqrestore(&phy->lock, flags); +} +EXPORT_SYMBOL_GPL(hisi_sas_phy_enable); + static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) { struct sas_ha_struct *sas_ha = sas_phy->ha; @@ -1112,10 +1130,10 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->maximum_linkrate = max; sas_phy->phy->minimum_linkrate = min; - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); msleep(100); hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); - hisi_hba->hw->phy_start(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); return 0; } @@ -1133,13 +1151,13 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, break; case PHY_FUNC_LINK_RESET: - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); msleep(100); - hisi_hba->hw->phy_start(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); break; case PHY_FUNC_DISABLE: - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); break; case PHY_FUNC_SET_LINK_RATE: @@ -1264,8 +1282,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, /* no error, but return the number of bytes of * underrun */ - dev_warn(dev, "abort tmf: task to dev %016llx " - "resp: 0x%x sts 0x%x underrun\n", + dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x sts 0x%x underrun\n", SAS_ADDR(device->sas_addr), task->task_status.resp, task->task_status.stat); @@ -1280,10 +1297,16 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, break; } - dev_warn(dev, "abort tmf: task to dev " - "%016llx resp: 0x%x status 0x%x\n", - SAS_ADDR(device->sas_addr), task->task_status.resp, - task->task_status.stat); + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_OPEN_REJECT) { + dev_warn(dev, "abort tmf: open reject failed\n"); + res = -EIO; + } else { + dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x status 0x%x\n", + SAS_ADDR(device->sas_addr), + task->task_status.resp, + task->task_status.stat); + } sas_free_task(task); task = NULL; } @@ -1423,13 +1446,13 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, _sas_port = sas_port; - if (DEV_IS_EXPANDER(dev->dev_type)) + if (dev_is_expander(dev->dev_type)) sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); } - } else if (old_state & (1 << phy_no)) - /* PHY down but was up before */ + } else { hisi_sas_phy_down(hisi_hba, phy_no, 0); + } } } @@ -1510,7 +1533,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) struct domain_device *port_dev = sas_port->port_dev; struct domain_device *device; - if (!port_dev || !DEV_IS_EXPANDER(port_dev->dev_type)) + if (!port_dev || !dev_is_expander(port_dev->dev_type)) continue; /* Try to find a SATA device */ @@ -1711,7 +1734,7 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; struct hisi_sas_tmf_task tmf_task; - int rc = TMF_RESP_FUNC_FAILED; + int rc; rc = hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0); @@ -1803,7 +1826,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) if (dev_is_sata(device)) { rc = hisi_sas_softreset_ata_disk(device); - if (rc) + if (rc == TMF_RESP_FUNC_FAILED) return TMF_RESP_FUNC_FAILED; } @@ -1880,7 +1903,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) struct domain_device *device = sas_dev->sas_device; if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device || - DEV_IS_EXPANDER(device->dev_type)) + dev_is_expander(device->dev_type)) continue; rc = hisi_sas_debug_I_T_nexus_reset(device); @@ -2100,10 +2123,8 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, } exit: - dev_dbg(dev, "internal task abort: task to dev %016llx task=%p " - "resp: 0x%x sts 0x%x\n", - SAS_ADDR(device->sas_addr), - task, + dev_dbg(dev, "internal task abort: task to dev %016llx task=%p resp: 0x%x sts 0x%x\n", + SAS_ADDR(device->sas_addr), task, task->task_status.resp, /* 0 is complete, -1 is undelivered */ task->task_status.stat); sas_free_task(task); @@ -2172,16 +2193,18 @@ static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) { struct asd_sas_phy *sas_phy = &phy->sas_phy; struct sas_phy *sphy = sas_phy->phy; - struct sas_phy_data *d = sphy->hostdata; + unsigned long flags; phy->phy_attached = 0; phy->phy_type = 0; phy->port = NULL; - if (d->enable) + spin_lock_irqsave(&phy->lock, flags); + if (phy->enable) sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; else sphy->negotiated_linkrate = SAS_PHY_DISABLED; + spin_unlock_irqrestore(&phy->lock, flags); } void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) @@ -2234,6 +2257,19 @@ void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba) } EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets); +int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type) +{ + struct hisi_hba *hisi_hba = shost_priv(shost); + + if (reset_type != SCSI_ADAPTER_RESET) + return -EOPNOTSUPP; + + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_sas_host_reset); + struct scsi_transport_template *hisi_sas_stt; EXPORT_SYMBOL_GPL(hisi_sas_stt); @@ -2439,6 +2475,14 @@ EXPORT_SYMBOL_GPL(hisi_sas_alloc); void hisi_sas_free(struct hisi_hba *hisi_hba) { + int i; + + for (i = 0; i < hisi_hba->n_phy; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + + del_timer_sync(&phy->timer); + } + if (hisi_hba->wq) destroy_workqueue(hisi_hba->wq); } @@ -2491,22 +2535,19 @@ int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) if (device_property_read_u32(dev, "ctrl-reset-reg", &hisi_hba->ctrl_reset_reg)) { - dev_err(dev, - "could not get property ctrl-reset-reg\n"); + dev_err(dev, "could not get property ctrl-reset-reg\n"); return -ENOENT; } if (device_property_read_u32(dev, "ctrl-reset-sts-reg", &hisi_hba->ctrl_reset_sts_reg)) { - dev_err(dev, - "could not get property ctrl-reset-sts-reg\n"); + dev_err(dev, "could not get property ctrl-reset-sts-reg\n"); return -ENOENT; } if (device_property_read_u32(dev, "ctrl-clock-ena-reg", &hisi_hba->ctrl_clock_ena_reg)) { - dev_err(dev, - "could not get property ctrl-clock-ena-reg\n"); + dev_err(dev, "could not get property ctrl-clock-ena-reg\n"); return -ENOENT; } } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 293807443480..3912216e8a4f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1,12 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015 Linaro Ltd. * Copyright (c) 2015 Hisilicon Limited. - * - * 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. - * */ #include "hisi_sas.h" @@ -798,16 +793,11 @@ static void start_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no) enable_phy_v1_hw(hisi_hba, phy_no); } -static void stop_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no) -{ - disable_phy_v1_hw(hisi_hba, phy_no); -} - static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no) { - stop_phy_v1_hw(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); msleep(100); - start_phy_v1_hw(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); } static void start_phys_v1_hw(struct timer_list *t) @@ -817,7 +807,7 @@ static void start_phys_v1_hw(struct timer_list *t) for (i = 0; i < hisi_hba->n_phy; i++) { hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x12a); - start_phy_v1_hw(hisi_hba, i); + hisi_sas_phy_enable(hisi_hba, i, 1); } } @@ -1695,8 +1685,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba) for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) { irq = platform_get_irq(pdev, idx); if (!irq) { - dev_err(dev, - "irq init: fail map phy interrupt %d\n", + dev_err(dev, "irq init: fail map phy interrupt %d\n", idx); return -ENOENT; } @@ -1704,8 +1693,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba) rc = devm_request_irq(dev, irq, phy_interrupts[j], 0, DRV_NAME " phy", phy); if (rc) { - dev_err(dev, "irq init: could not request " - "phy interrupt %d, rc=%d\n", + dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n", irq, rc); return -ENOENT; } @@ -1742,8 +1730,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba) rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0, DRV_NAME " fatal", hisi_hba); if (rc) { - dev_err(dev, - "irq init: could not request fatal interrupt %d, rc=%d\n", + dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n", irq, rc); return -ENOENT; } @@ -1823,6 +1810,7 @@ static struct scsi_host_template sht_v1_hw = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = host_attrs_v1_hw, + .host_reset = hisi_sas_host_reset, }; static const struct hisi_sas_hw hisi_sas_v1_hw = { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 89160ab3efb0..e9b15d45f98f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1,12 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2016 Linaro Ltd. * Copyright (c) 2016 Hisilicon Limited. - * - * 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. - * */ #include "hisi_sas.h" @@ -427,70 +422,70 @@ static const struct hisi_sas_hw_error one_bit_ecc_errors[] = { .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF), .msk = HGC_DQE_ECC_1B_ADDR_MSK, .shift = HGC_DQE_ECC_1B_ADDR_OFF, - .msg = "hgc_dqe_acc1b_intr found: Ram address is 0x%08X\n", + .msg = "hgc_dqe_ecc1b_intr", .reg = HGC_DQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF), .msk = HGC_IOST_ECC_1B_ADDR_MSK, .shift = HGC_IOST_ECC_1B_ADDR_OFF, - .msg = "hgc_iost_acc1b_intr found: Ram address is 0x%08X\n", + .msg = "hgc_iost_ecc1b_intr", .reg = HGC_IOST_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF), .msk = HGC_ITCT_ECC_1B_ADDR_MSK, .shift = HGC_ITCT_ECC_1B_ADDR_OFF, - .msg = "hgc_itct_acc1b_intr found: am address is 0x%08X\n", + .msg = "hgc_itct_ecc1b_intr", .reg = HGC_ITCT_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF), .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF, - .msg = "hgc_iostl_acc1b_intr found: memory address is 0x%08X\n", + .msg = "hgc_iostl_ecc1b_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF), .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF, - .msg = "hgc_itctl_acc1b_intr found: memory address is 0x%08X\n", + .msg = "hgc_itctl_ecc1b_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF), .msk = HGC_CQE_ECC_1B_ADDR_MSK, .shift = HGC_CQE_ECC_1B_ADDR_OFF, - .msg = "hgc_cqe_acc1b_intr found: Ram address is 0x%08X\n", + .msg = "hgc_cqe_ecc1b_intr", .reg = HGC_CQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF, - .msg = "rxm_mem0_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem0_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF, - .msg = "rxm_mem1_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem1_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF, - .msg = "rxm_mem2_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem2_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK, .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF, - .msg = "rxm_mem3_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem3_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS15, }, }; @@ -500,70 +495,70 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = { .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF), .msk = HGC_DQE_ECC_MB_ADDR_MSK, .shift = HGC_DQE_ECC_MB_ADDR_OFF, - .msg = "hgc_dqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_dqe_eccbad_intr", .reg = HGC_DQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF), .msk = HGC_IOST_ECC_MB_ADDR_MSK, .shift = HGC_IOST_ECC_MB_ADDR_OFF, - .msg = "hgc_iost_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_iost_eccbad_intr", .reg = HGC_IOST_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF), .msk = HGC_ITCT_ECC_MB_ADDR_MSK, .shift = HGC_ITCT_ECC_MB_ADDR_OFF, - .msg = "hgc_itct_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_itct_eccbad_intr", .reg = HGC_ITCT_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF), .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF, - .msg = "hgc_iostl_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "hgc_iostl_eccbad_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF), .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF, - .msg = "hgc_itctl_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "hgc_itctl_eccbad_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF), .msk = HGC_CQE_ECC_MB_ADDR_MSK, .shift = HGC_CQE_ECC_MB_ADDR_OFF, - .msg = "hgc_cqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_cqe_eccbad_intr", .reg = HGC_CQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF, - .msg = "rxm_mem0_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem0_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF, - .msg = "rxm_mem1_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem1_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF, - .msg = "rxm_mem2_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem2_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK, .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF, - .msg = "rxm_mem3_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem3_eccbad_intr", .reg = HGC_RXM_DFX_STATUS15, }, }; @@ -949,7 +944,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -1546,14 +1541,14 @@ static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no) struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; u32 txid_auto; - disable_phy_v2_hw(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); if (phy->identify.device_type == SAS_END_DEVICE) { txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, txid_auto | TX_HARDRST_MSK); } msleep(100); - start_phy_v2_hw(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); } static void phy_get_events_v2_hw(struct hisi_hba *hisi_hba, int phy_no) @@ -1586,7 +1581,7 @@ static void phys_init_v2_hw(struct hisi_hba *hisi_hba) if (!sas_phy->phy->enabled) continue; - start_phy_v2_hw(hisi_hba, i); + hisi_sas_phy_enable(hisi_hba, i, 1); } } @@ -2423,14 +2418,12 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) slot_err_v2_hw(hisi_hba, task, slot, 2); if (ts->stat != SAS_DATA_UNDERRUN) - dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d " - "CQ hdr: 0x%x 0x%x 0x%x 0x%x " - "Error info: 0x%x 0x%x 0x%x 0x%x\n", - slot->idx, task, sas_dev->device_id, - complete_hdr->dw0, complete_hdr->dw1, - complete_hdr->act, complete_hdr->dw3, - error_info[0], error_info[1], - error_info[2], error_info[3]); + dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", + slot->idx, task, sas_dev->device_id, + complete_hdr->dw0, complete_hdr->dw1, + complete_hdr->act, complete_hdr->dw3, + error_info[0], error_info[1], + error_info[2], error_info[3]); if (unlikely(slot->abort)) return ts->stat; @@ -2502,7 +2495,7 @@ out: spin_lock_irqsave(&device->done_lock, flags); if (test_bit(SAS_HA_FROZEN, &ha->state)) { spin_unlock_irqrestore(&device->done_lock, flags); - dev_info(dev, "slot complete: task(%p) ignored\n ", + dev_info(dev, "slot complete: task(%p) ignored\n", task); return sts; } @@ -2533,7 +2526,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, /* create header */ /* dw0 */ dw0 = port->id << CMD_HDR_PORT_OFF; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) dw0 |= 3 << CMD_HDR_CMD_OFF; else dw0 |= 4 << CMD_HDR_CMD_OFF; @@ -2935,7 +2928,7 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p) if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) { dev_warn(dev, "phy%d identify timeout\n", - phy_no); + phy_no); hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); } @@ -2980,7 +2973,8 @@ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value) val = hisi_sas_read32(hisi_hba, ecc_error->reg); val &= ecc_error->msk; val >>= ecc_error->shift; - dev_warn(dev, ecc_error->msg, val); + dev_warn(dev, "%s found: mem addr is 0x%08X\n", + ecc_error->msg, val); } } } @@ -2999,7 +2993,8 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, val = hisi_sas_read32(hisi_hba, ecc_error->reg); val &= ecc_error->msk; val >>= ecc_error->shift; - dev_err(dev, ecc_error->msg, irq_value, val); + dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n", + ecc_error->msg, irq_value, val); queue_work(hisi_hba->wq, &hisi_hba->rst_work); } } @@ -3036,7 +3031,7 @@ static const struct hisi_sas_hw_error axi_error[] = { { .msk = BIT(5), .msg = "SATA_AXI_R_ERR" }, { .msk = BIT(6), .msg = "DQE_AXI_R_ERR" }, { .msk = BIT(7), .msg = "CQE_AXI_W_ERR" }, - {}, + {} }; static const struct hisi_sas_hw_error fifo_error[] = { @@ -3045,7 +3040,7 @@ static const struct hisi_sas_hw_error fifo_error[] = { { .msk = BIT(10), .msg = "GETDQE_FIFO" }, { .msk = BIT(11), .msg = "CMDP_FIFO" }, { .msk = BIT(12), .msg = "AWTCTRL_FIFO" }, - {}, + {} }; static const struct hisi_sas_hw_error fatal_axi_errors[] = { @@ -3109,12 +3104,12 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) if (!(err_value & sub->msk)) continue; dev_err(dev, "%s (0x%x) found!\n", - sub->msg, irq_value); + sub->msg, irq_value); queue_work(hisi_hba->wq, &hisi_hba->rst_work); } } else { dev_err(dev, "%s (0x%x) found!\n", - axi_error->msg, irq_value); + axi_error->msg, irq_value); queue_work(hisi_hba->wq, &hisi_hba->rst_work); } } @@ -3258,7 +3253,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) /* check ERR bit of Status Register */ if (fis->status & ATA_ERR) { dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no, - fis->status); + fis->status); hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); res = IRQ_NONE; goto end; @@ -3349,8 +3344,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) rc = devm_request_irq(dev, irq, phy_interrupts[i], 0, DRV_NAME " phy", hisi_hba); if (rc) { - dev_err(dev, "irq init: could not request " - "phy interrupt %d, rc=%d\n", + dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; goto free_phy_int_irqs; @@ -3364,8 +3358,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0, DRV_NAME " sata", phy); if (rc) { - dev_err(dev, "irq init: could not request " - "sata interrupt %d, rc=%d\n", + dev_err(dev, "irq init: could not request sata interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; goto free_sata_int_irqs; @@ -3377,8 +3370,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0, DRV_NAME " fatal", hisi_hba); if (rc) { - dev_err(dev, - "irq init: could not request fatal interrupt %d, rc=%d\n", + dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; goto free_fatal_int_irqs; @@ -3393,8 +3385,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0, DRV_NAME " cq", cq); if (rc) { - dev_err(dev, - "irq init: could not request cq interrupt %d, rc=%d\n", + dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; goto free_cq_int_irqs; @@ -3546,7 +3537,7 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, break; default: dev_err(dev, "write gpio: unsupported or bad reg type %d\n", - reg_type); + reg_type); return -EINVAL; } @@ -3599,6 +3590,7 @@ static struct scsi_host_template sht_v2_hw = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = host_attrs_v2_hw, + .host_reset = hisi_sas_host_reset, }; static const struct hisi_sas_hw hisi_sas_v2_hw = { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 086695a4099f..5f0f6df11adf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1,11 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Hisilicon Limited. - * - * 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. - * */ #include "hisi_sas.h" @@ -28,6 +23,7 @@ #define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF) #define ITCT_DEV_OFF 0 #define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF) +#define SAS_AXI_USER3 0x50 #define IO_SATA_BROKEN_MSG_ADDR_LO 0x58 #define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c #define SATA_INITI_D2H_STORE_ADDR_LO 0x60 @@ -52,7 +48,36 @@ #define CFG_ABT_SET_IPTT_DONE 0xd8 #define CFG_ABT_SET_IPTT_DONE_OFF 0 #define HGC_IOMB_PROC1_STATUS 0x104 +#define HGC_LM_DFX_STATUS2 0x128 +#define HGC_LM_DFX_STATUS2_IOSTLIST_OFF 0 +#define HGC_LM_DFX_STATUS2_IOSTLIST_MSK (0xfff << \ + HGC_LM_DFX_STATUS2_IOSTLIST_OFF) +#define HGC_LM_DFX_STATUS2_ITCTLIST_OFF 12 +#define HGC_LM_DFX_STATUS2_ITCTLIST_MSK (0x7ff << \ + HGC_LM_DFX_STATUS2_ITCTLIST_OFF) +#define HGC_CQE_ECC_ADDR 0x13c +#define HGC_CQE_ECC_1B_ADDR_OFF 0 +#define HGC_CQE_ECC_1B_ADDR_MSK (0x3f << HGC_CQE_ECC_1B_ADDR_OFF) +#define HGC_CQE_ECC_MB_ADDR_OFF 8 +#define HGC_CQE_ECC_MB_ADDR_MSK (0x3f << HGC_CQE_ECC_MB_ADDR_OFF) +#define HGC_IOST_ECC_ADDR 0x140 +#define HGC_IOST_ECC_1B_ADDR_OFF 0 +#define HGC_IOST_ECC_1B_ADDR_MSK (0x3ff << HGC_IOST_ECC_1B_ADDR_OFF) +#define HGC_IOST_ECC_MB_ADDR_OFF 16 +#define HGC_IOST_ECC_MB_ADDR_MSK (0x3ff << HGC_IOST_ECC_MB_ADDR_OFF) +#define HGC_DQE_ECC_ADDR 0x144 +#define HGC_DQE_ECC_1B_ADDR_OFF 0 +#define HGC_DQE_ECC_1B_ADDR_MSK (0xfff << HGC_DQE_ECC_1B_ADDR_OFF) +#define HGC_DQE_ECC_MB_ADDR_OFF 16 +#define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF) #define CHNL_INT_STATUS 0x148 +#define HGC_ITCT_ECC_ADDR 0x150 +#define HGC_ITCT_ECC_1B_ADDR_OFF 0 +#define HGC_ITCT_ECC_1B_ADDR_MSK (0x3ff << \ + HGC_ITCT_ECC_1B_ADDR_OFF) +#define HGC_ITCT_ECC_MB_ADDR_OFF 16 +#define HGC_ITCT_ECC_MB_ADDR_MSK (0x3ff << \ + HGC_ITCT_ECC_MB_ADDR_OFF) #define HGC_AXI_FIFO_ERR_INFO 0x154 #define AXI_ERR_INFO_OFF 0 #define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF) @@ -81,6 +106,10 @@ #define ENT_INT_SRC3_ITC_INT_OFF 15 #define ENT_INT_SRC3_ITC_INT_MSK (0x1 << ENT_INT_SRC3_ITC_INT_OFF) #define ENT_INT_SRC3_ABT_OFF 16 +#define ENT_INT_SRC3_DQE_POISON_OFF 18 +#define ENT_INT_SRC3_IOST_POISON_OFF 19 +#define ENT_INT_SRC3_ITCT_POISON_OFF 20 +#define ENT_INT_SRC3_ITCT_NCQ_POISON_OFF 21 #define ENT_INT_SRC_MSK1 0x1c4 #define ENT_INT_SRC_MSK2 0x1c8 #define ENT_INT_SRC_MSK3 0x1cc @@ -90,6 +119,28 @@ #define HGC_COM_INT_MSK 0x1d8 #define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF) #define SAS_ECC_INTR 0x1e8 +#define SAS_ECC_INTR_DQE_ECC_1B_OFF 0 +#define SAS_ECC_INTR_DQE_ECC_MB_OFF 1 +#define SAS_ECC_INTR_IOST_ECC_1B_OFF 2 +#define SAS_ECC_INTR_IOST_ECC_MB_OFF 3 +#define SAS_ECC_INTR_ITCT_ECC_1B_OFF 4 +#define SAS_ECC_INTR_ITCT_ECC_MB_OFF 5 +#define SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF 6 +#define SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF 7 +#define SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF 8 +#define SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF 9 +#define SAS_ECC_INTR_CQE_ECC_1B_OFF 10 +#define SAS_ECC_INTR_CQE_ECC_MB_OFF 11 +#define SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF 12 +#define SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF 13 +#define SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF 14 +#define SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF 15 +#define SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF 16 +#define SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF 17 +#define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF 18 +#define SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF 19 +#define SAS_ECC_INTR_OOO_RAM_ECC_1B_OFF 20 +#define SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF 21 #define SAS_ECC_INTR_MSK 0x1ec #define HGC_ERR_STAT_EN 0x238 #define CQE_SEND_CNT 0x248 @@ -105,6 +156,20 @@ #define COMPL_Q_0_DEPTH 0x4e8 #define COMPL_Q_0_WR_PTR 0x4ec #define COMPL_Q_0_RD_PTR 0x4f0 +#define HGC_RXM_DFX_STATUS14 0xae8 +#define HGC_RXM_DFX_STATUS14_MEM0_OFF 0 +#define HGC_RXM_DFX_STATUS14_MEM0_MSK (0x1ff << \ + HGC_RXM_DFX_STATUS14_MEM0_OFF) +#define HGC_RXM_DFX_STATUS14_MEM1_OFF 9 +#define HGC_RXM_DFX_STATUS14_MEM1_MSK (0x1ff << \ + HGC_RXM_DFX_STATUS14_MEM1_OFF) +#define HGC_RXM_DFX_STATUS14_MEM2_OFF 18 +#define HGC_RXM_DFX_STATUS14_MEM2_MSK (0x1ff << \ + HGC_RXM_DFX_STATUS14_MEM2_OFF) +#define HGC_RXM_DFX_STATUS15 0xaec +#define HGC_RXM_DFX_STATUS15_MEM3_OFF 0 +#define HGC_RXM_DFX_STATUS15_MEM3_MSK (0x1ff << \ + HGC_RXM_DFX_STATUS15_MEM3_OFF) #define AWQOS_AWCACHE_CFG 0xc84 #define ARQOS_ARCACHE_CFG 0xc88 #define HILINK_ERR_DFX 0xe04 @@ -172,14 +237,18 @@ #define CHL_INT0_PHY_RDY_OFF 5 #define CHL_INT0_PHY_RDY_MSK (0x1 << CHL_INT0_PHY_RDY_OFF) #define CHL_INT1 (PORT_BASE + 0x1b8) -#define CHL_INT1_DMAC_TX_ECC_ERR_OFF 15 -#define CHL_INT1_DMAC_TX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF) -#define CHL_INT1_DMAC_RX_ECC_ERR_OFF 17 -#define CHL_INT1_DMAC_RX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF) +#define CHL_INT1_DMAC_TX_ECC_MB_ERR_OFF 15 +#define CHL_INT1_DMAC_TX_ECC_1B_ERR_OFF 16 +#define CHL_INT1_DMAC_RX_ECC_MB_ERR_OFF 17 +#define CHL_INT1_DMAC_RX_ECC_1B_ERR_OFF 18 #define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF 19 #define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF 20 #define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF 21 #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF 22 +#define CHL_INT1_DMAC_TX_FIFO_ERR_OFF 23 +#define CHL_INT1_DMAC_RX_FIFO_ERR_OFF 24 +#define CHL_INT1_DMAC_TX_AXI_RUSER_ERR_OFF 26 +#define CHL_INT1_DMAC_RX_AXI_RUSER_ERR_OFF 27 #define CHL_INT2 (PORT_BASE + 0x1bc) #define CHL_INT2_SL_IDAF_TOUT_CONF_OFF 0 #define CHL_INT2_RX_DISP_ERR_OFF 28 @@ -227,10 +296,8 @@ #define AM_CFG_SINGLE_PORT_MAX_TRANS (0x5014) #define AXI_CFG (0x5100) #define AM_ROB_ECC_ERR_ADDR (0x510c) -#define AM_ROB_ECC_ONEBIT_ERR_ADDR_OFF 0 -#define AM_ROB_ECC_ONEBIT_ERR_ADDR_MSK (0xff << AM_ROB_ECC_ONEBIT_ERR_ADDR_OFF) -#define AM_ROB_ECC_MULBIT_ERR_ADDR_OFF 8 -#define AM_ROB_ECC_MULBIT_ERR_ADDR_MSK (0xff << AM_ROB_ECC_MULBIT_ERR_ADDR_OFF) +#define AM_ROB_ECC_ERR_ADDR_OFF 0 +#define AM_ROB_ECC_ERR_ADDR_MSK 0xffffffff /* RAS registers need init */ #define RAS_BASE (0x6000) @@ -408,6 +475,10 @@ struct hisi_sas_err_record_v3 { #define BASE_VECTORS_V3_HW 16 #define MIN_AFFINE_VECTORS_V3_HW (BASE_VECTORS_V3_HW + 1) +enum { + DSM_FUNC_ERR_HANDLE_MSI = 0, +}; + static bool hisi_sas_intr_conv; MODULE_PARM_DESC(intr_conv, "interrupt converge enable (0-1)"); @@ -474,12 +545,12 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, static void init_reg_v3_hw(struct hisi_hba *hisi_hba) { - struct pci_dev *pdev = hisi_hba->pci_dev; int i; /* Global registers init */ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, (u32)((1ULL << hisi_hba->queue_count) - 1)); + hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0); hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400); hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); @@ -494,14 +565,11 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe); - if (pdev->revision >= 0x21) - hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffff7aff); - else - hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xfffe20ff); + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffc220ff); hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0); - hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x0); + hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x155555); hisi_sas_write32(hisi_hba, AWQOS_AWCACHE_CFG, 0xf0f0); hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0); for (i = 0; i < hisi_hba->queue_count; i++) @@ -532,12 +600,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff); hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000); - if (pdev->revision >= 0x21) - hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, - 0xffffffff); - else - hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, - 0xff87ffff); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xf2057fff); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe); hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0); @@ -691,7 +754,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -804,6 +867,8 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba) static int hw_init_v3_hw(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; + union acpi_object *obj; + guid_t guid; int rc; rc = reset_hw_v3_hw(hisi_hba); @@ -815,6 +880,19 @@ static int hw_init_v3_hw(struct hisi_hba *hisi_hba) msleep(100); init_reg_v3_hw(hisi_hba); + if (guid_parse("D5918B4B-37AE-4E10-A99F-E5E8A6EF4C1F", &guid)) { + dev_err(dev, "Parse GUID failed\n"); + return -EINVAL; + } + + /* Switch over to MSI handling , from PCI AER default */ + obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &guid, 0, + DSM_FUNC_ERR_HANDLE_MSI, NULL); + if (!obj) + dev_warn(dev, "Switch over to MSI handling failed\n"); + else + ACPI_FREE(obj); + return 0; } @@ -830,8 +908,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) { u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); + u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2_MSK); + static const u32 msk = BIT(CHL_INT2_RX_DISP_ERR_OFF) | + BIT(CHL_INT2_RX_CODE_ERR_OFF) | + BIT(CHL_INT2_RX_INVLD_DW_OFF); u32 state; + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, msk | irq_msk); + cfg &= ~PHY_CFG_ENA_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); @@ -842,6 +926,15 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) cfg |= PHY_CFG_PHY_RST_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); } + + udelay(1); + + hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_INVLD_DW); + hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DISP_ERR); + hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_CODE_ERR); + + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, msk); + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, irq_msk); } static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) @@ -856,14 +949,14 @@ static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no) struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; u32 txid_auto; - disable_phy_v3_hw(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); if (phy->identify.device_type == SAS_END_DEVICE) { txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, txid_auto | TX_HARDRST_MSK); } msleep(100); - start_phy_v3_hw(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); } static enum sas_linkrate phy_get_max_linkrate_v3_hw(void) @@ -882,7 +975,7 @@ static void phys_init_v3_hw(struct hisi_hba *hisi_hba) if (!sas_phy->phy->enabled) continue; - start_phy_v3_hw(hisi_hba, i); + hisi_sas_phy_enable(hisi_hba, i, 1); } } @@ -929,7 +1022,7 @@ get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) DLVRY_Q_0_RD_PTR + (queue * 0x14)); if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { dev_warn(dev, "full queue=%d r=%d w=%d\n", - queue, r, w); + queue, r, w); return -EAGAIN; } @@ -1260,10 +1353,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, u32 dw1 = 0, dw2 = 0; hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); else - hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF); + hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF); switch (task->data_dir) { case DMA_TO_DEVICE: @@ -1331,7 +1424,7 @@ static void prep_abort_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_port *port = slot->port; /* dw0 */ - hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ + hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/ (port->id << CMD_HDR_PORT_OFF) | (dev_is_sata(dev) << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | @@ -1380,6 +1473,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) struct hisi_sas_initial_fis *initial_fis; struct dev_to_host_fis *fis; u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; + struct Scsi_Host *shost = hisi_hba->shost; dev_info(dev, "phyup: phy%d link_rate=%d(sata)\n", phy_no, link_rate); initial_fis = &hisi_hba->initial_fis[phy_no]; @@ -1396,6 +1490,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) sas_phy->oob_mode = SATA_OOB_MODE; attached_sas_addr[0] = 0x50; + attached_sas_addr[6] = shost->host_no; attached_sas_addr[7] = phy_no; memcpy(sas_phy->attached_sas_addr, attached_sas_addr, @@ -1540,6 +1635,14 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) static const struct hisi_sas_hw_error port_axi_error[] = { { + .irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_MB_ERR_OFF), + .msg = "dmac_tx_ecc_bad_err", + }, + { + .irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_MB_ERR_OFF), + .msg = "dmac_rx_ecc_bad_err", + }, + { .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF), .msg = "dma_tx_axi_wr_err", }, @@ -1555,6 +1658,22 @@ static const struct hisi_sas_hw_error port_axi_error[] = { .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF), .msg = "dma_rx_axi_rd_err", }, + { + .irq_msk = BIT(CHL_INT1_DMAC_TX_FIFO_ERR_OFF), + .msg = "dma_tx_fifo_err", + }, + { + .irq_msk = BIT(CHL_INT1_DMAC_RX_FIFO_ERR_OFF), + .msg = "dma_rx_fifo_err", + }, + { + .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RUSER_ERR_OFF), + .msg = "dma_tx_axi_ruser_err", + }, + { + .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RUSER_ERR_OFF), + .msg = "dma_rx_axi_ruser_err", + }, }; static void handle_chl_int1_v3_hw(struct hisi_hba *hisi_hba, int phy_no) @@ -1719,6 +1838,122 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) return IRQ_HANDLED; } +static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = { + { + .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF), + .msk = HGC_DQE_ECC_MB_ADDR_MSK, + .shift = HGC_DQE_ECC_MB_ADDR_OFF, + .msg = "hgc_dqe_eccbad_intr", + .reg = HGC_DQE_ECC_ADDR, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF), + .msk = HGC_IOST_ECC_MB_ADDR_MSK, + .shift = HGC_IOST_ECC_MB_ADDR_OFF, + .msg = "hgc_iost_eccbad_intr", + .reg = HGC_IOST_ECC_ADDR, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF), + .msk = HGC_ITCT_ECC_MB_ADDR_MSK, + .shift = HGC_ITCT_ECC_MB_ADDR_OFF, + .msg = "hgc_itct_eccbad_intr", + .reg = HGC_ITCT_ECC_ADDR, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF), + .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK, + .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF, + .msg = "hgc_iostl_eccbad_intr", + .reg = HGC_LM_DFX_STATUS2, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF), + .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK, + .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF, + .msg = "hgc_itctl_eccbad_intr", + .reg = HGC_LM_DFX_STATUS2, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF), + .msk = HGC_CQE_ECC_MB_ADDR_MSK, + .shift = HGC_CQE_ECC_MB_ADDR_OFF, + .msg = "hgc_cqe_eccbad_intr", + .reg = HGC_CQE_ECC_ADDR, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF), + .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK, + .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF, + .msg = "rxm_mem0_eccbad_intr", + .reg = HGC_RXM_DFX_STATUS14, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF), + .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK, + .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF, + .msg = "rxm_mem1_eccbad_intr", + .reg = HGC_RXM_DFX_STATUS14, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF), + .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK, + .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF, + .msg = "rxm_mem2_eccbad_intr", + .reg = HGC_RXM_DFX_STATUS14, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF), + .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK, + .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF, + .msg = "rxm_mem3_eccbad_intr", + .reg = HGC_RXM_DFX_STATUS15, + }, + { + .irq_msk = BIT(SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF), + .msk = AM_ROB_ECC_ERR_ADDR_MSK, + .shift = AM_ROB_ECC_ERR_ADDR_OFF, + .msg = "ooo_ram_eccbad_intr", + .reg = AM_ROB_ECC_ERR_ADDR, + }, +}; + +static void multi_bit_ecc_error_process_v3_hw(struct hisi_hba *hisi_hba, + u32 irq_value) +{ + struct device *dev = hisi_hba->dev; + const struct hisi_sas_hw_error *ecc_error; + u32 val; + int i; + + for (i = 0; i < ARRAY_SIZE(multi_bit_ecc_errors); i++) { + ecc_error = &multi_bit_ecc_errors[i]; + if (irq_value & ecc_error->irq_msk) { + val = hisi_sas_read32(hisi_hba, ecc_error->reg); + val &= ecc_error->msk; + val >>= ecc_error->shift; + dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n", + ecc_error->msg, irq_value, val); + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + } + } +} + +static void fatal_ecc_int_v3_hw(struct hisi_hba *hisi_hba) +{ + u32 irq_value, irq_msk; + + irq_msk = hisi_sas_read32(hisi_hba, SAS_ECC_INTR_MSK); + hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk | 0xffffffff); + + irq_value = hisi_sas_read32(hisi_hba, SAS_ECC_INTR); + if (irq_value) + multi_bit_ecc_error_process_v3_hw(hisi_hba, irq_value); + + hisi_sas_write32(hisi_hba, SAS_ECC_INTR, irq_value); + hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk); +} + static const struct hisi_sas_hw_error axi_error[] = { { .msk = BIT(0), .msg = "IOST_AXI_W_ERR" }, { .msk = BIT(1), .msg = "IOST_AXI_R_ERR" }, @@ -1728,7 +1963,7 @@ static const struct hisi_sas_hw_error axi_error[] = { { .msk = BIT(5), .msg = "SATA_AXI_R_ERR" }, { .msk = BIT(6), .msg = "DQE_AXI_R_ERR" }, { .msk = BIT(7), .msg = "CQE_AXI_W_ERR" }, - {}, + {} }; static const struct hisi_sas_hw_error fifo_error[] = { @@ -1737,7 +1972,7 @@ static const struct hisi_sas_hw_error fifo_error[] = { { .msk = BIT(10), .msg = "GETDQE_FIFO" }, { .msk = BIT(11), .msg = "CMDP_FIFO" }, { .msk = BIT(12), .msg = "AWTCTRL_FIFO" }, - {}, + {} }; static const struct hisi_sas_hw_error fatal_axi_error[] = { @@ -1771,6 +2006,23 @@ static const struct hisi_sas_hw_error fatal_axi_error[] = { .irq_msk = BIT(ENT_INT_SRC3_ABT_OFF), .msg = "SAS_HGC_ABT fetch LM list", }, + { + .irq_msk = BIT(ENT_INT_SRC3_DQE_POISON_OFF), + .msg = "read dqe poison", + }, + { + .irq_msk = BIT(ENT_INT_SRC3_IOST_POISON_OFF), + .msg = "read iost poison", + }, + { + .irq_msk = BIT(ENT_INT_SRC3_ITCT_POISON_OFF), + .msg = "read itct poison", + }, + { + .irq_msk = BIT(ENT_INT_SRC3_ITCT_NCQ_POISON_OFF), + .msg = "read itct ncq poison", + }, + }; static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p) @@ -1823,6 +2075,8 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p) } } + fatal_ecc_int_v3_hw(hisi_hba); + if (irq_value & BIT(ENT_INT_SRC3_ITC_INT_OFF)) { u32 reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR); u32 dev_id = reg_val & ITCT_DEV_MSK; @@ -1966,13 +2220,11 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) slot_err_v3_hw(hisi_hba, task, slot); if (ts->stat != SAS_DATA_UNDERRUN) - dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d " - "CQ hdr: 0x%x 0x%x 0x%x 0x%x " - "Error info: 0x%x 0x%x 0x%x 0x%x\n", - slot->idx, task, sas_dev->device_id, - dw0, dw1, complete_hdr->act, dw3, - error_info[0], error_info[1], - error_info[2], error_info[3]); + dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", + slot->idx, task, sas_dev->device_id, + dw0, dw1, complete_hdr->act, dw3, + error_info[0], error_info[1], + error_info[2], error_info[3]); if (unlikely(slot->abort)) return ts->stat; goto out; @@ -2205,8 +2457,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) cq_interrupt_v3_hw, irqflags, DRV_NAME " cq", cq); if (rc) { - dev_err(dev, - "could not request cq%d interrupt, rc=%d\n", + dev_err(dev, "could not request cq%d interrupt, rc=%d\n", i, rc); rc = -ENOENT; goto free_cq_irqs; @@ -2362,7 +2613,7 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type, break; default: dev_err(dev, "write gpio: unsupported or bad reg type %d\n", - reg_type); + reg_type); return -EINVAL; } @@ -2678,6 +2929,7 @@ static struct scsi_host_template sht_v3_hw = { .ioctl = sas_ioctl, .shost_attrs = host_attrs_v3_hw, .tag_alloc_policy = BLK_TAG_ALLOC_RR, + .host_reset = hisi_sas_host_reset, }; static const struct hisi_sas_hw hisi_sas_v3_hw = { @@ -2800,7 +3052,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) hisi_hba->regs = pcim_iomap(pdev, 5, 0); if (!hisi_hba->regs) { - dev_err(dev, "cannot map register.\n"); + dev_err(dev, "cannot map register\n"); rc = -ENOMEM; goto err_out_ha; } @@ -2921,161 +3173,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) scsi_host_put(shost); } -static const struct hisi_sas_hw_error sas_ras_intr0_nfe[] = { - { .irq_msk = BIT(19), .msg = "HILINK_INT" }, - { .irq_msk = BIT(20), .msg = "HILINK_PLL0_OUT_OF_LOCK" }, - { .irq_msk = BIT(21), .msg = "HILINK_PLL1_OUT_OF_LOCK" }, - { .irq_msk = BIT(22), .msg = "HILINK_LOSS_OF_REFCLK0" }, - { .irq_msk = BIT(23), .msg = "HILINK_LOSS_OF_REFCLK1" }, - { .irq_msk = BIT(24), .msg = "DMAC0_TX_POISON" }, - { .irq_msk = BIT(25), .msg = "DMAC1_TX_POISON" }, - { .irq_msk = BIT(26), .msg = "DMAC2_TX_POISON" }, - { .irq_msk = BIT(27), .msg = "DMAC3_TX_POISON" }, - { .irq_msk = BIT(28), .msg = "DMAC4_TX_POISON" }, - { .irq_msk = BIT(29), .msg = "DMAC5_TX_POISON" }, - { .irq_msk = BIT(30), .msg = "DMAC6_TX_POISON" }, - { .irq_msk = BIT(31), .msg = "DMAC7_TX_POISON" }, -}; - -static const struct hisi_sas_hw_error sas_ras_intr1_nfe[] = { - { .irq_msk = BIT(0), .msg = "RXM_CFG_MEM3_ECC2B_INTR" }, - { .irq_msk = BIT(1), .msg = "RXM_CFG_MEM2_ECC2B_INTR" }, - { .irq_msk = BIT(2), .msg = "RXM_CFG_MEM1_ECC2B_INTR" }, - { .irq_msk = BIT(3), .msg = "RXM_CFG_MEM0_ECC2B_INTR" }, - { .irq_msk = BIT(4), .msg = "HGC_CQE_ECC2B_INTR" }, - { .irq_msk = BIT(5), .msg = "LM_CFG_IOSTL_ECC2B_INTR" }, - { .irq_msk = BIT(6), .msg = "LM_CFG_ITCTL_ECC2B_INTR" }, - { .irq_msk = BIT(7), .msg = "HGC_ITCT_ECC2B_INTR" }, - { .irq_msk = BIT(8), .msg = "HGC_IOST_ECC2B_INTR" }, - { .irq_msk = BIT(9), .msg = "HGC_DQE_ECC2B_INTR" }, - { .irq_msk = BIT(10), .msg = "DMAC0_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(11), .msg = "DMAC1_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(12), .msg = "DMAC2_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(13), .msg = "DMAC3_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(14), .msg = "DMAC4_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(15), .msg = "DMAC5_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(16), .msg = "DMAC6_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(17), .msg = "DMAC7_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(18), .msg = "OOO_RAM_ECC2B_INTR" }, - { .irq_msk = BIT(20), .msg = "HGC_DQE_POISON_INTR" }, - { .irq_msk = BIT(21), .msg = "HGC_IOST_POISON_INTR" }, - { .irq_msk = BIT(22), .msg = "HGC_ITCT_POISON_INTR" }, - { .irq_msk = BIT(23), .msg = "HGC_ITCT_NCQ_POISON_INTR" }, - { .irq_msk = BIT(24), .msg = "DMAC0_RX_POISON" }, - { .irq_msk = BIT(25), .msg = "DMAC1_RX_POISON" }, - { .irq_msk = BIT(26), .msg = "DMAC2_RX_POISON" }, - { .irq_msk = BIT(27), .msg = "DMAC3_RX_POISON" }, - { .irq_msk = BIT(28), .msg = "DMAC4_RX_POISON" }, - { .irq_msk = BIT(29), .msg = "DMAC5_RX_POISON" }, - { .irq_msk = BIT(30), .msg = "DMAC6_RX_POISON" }, - { .irq_msk = BIT(31), .msg = "DMAC7_RX_POISON" }, -}; - -static const struct hisi_sas_hw_error sas_ras_intr2_nfe[] = { - { .irq_msk = BIT(0), .msg = "DMAC0_AXI_BUS_ERR" }, - { .irq_msk = BIT(1), .msg = "DMAC1_AXI_BUS_ERR" }, - { .irq_msk = BIT(2), .msg = "DMAC2_AXI_BUS_ERR" }, - { .irq_msk = BIT(3), .msg = "DMAC3_AXI_BUS_ERR" }, - { .irq_msk = BIT(4), .msg = "DMAC4_AXI_BUS_ERR" }, - { .irq_msk = BIT(5), .msg = "DMAC5_AXI_BUS_ERR" }, - { .irq_msk = BIT(6), .msg = "DMAC6_AXI_BUS_ERR" }, - { .irq_msk = BIT(7), .msg = "DMAC7_AXI_BUS_ERR" }, - { .irq_msk = BIT(8), .msg = "DMAC0_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(9), .msg = "DMAC1_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(10), .msg = "DMAC2_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(11), .msg = "DMAC3_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(12), .msg = "DMAC4_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(13), .msg = "DMAC5_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(14), .msg = "DMAC6_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(15), .msg = "DMAC7_FIFO_OMIT_ERR" }, - { .irq_msk = BIT(16), .msg = "HGC_RLSE_SLOT_UNMATCH" }, - { .irq_msk = BIT(17), .msg = "HGC_LM_ADD_FCH_LIST_ERR" }, - { .irq_msk = BIT(18), .msg = "HGC_AXI_BUS_ERR" }, - { .irq_msk = BIT(19), .msg = "HGC_FIFO_OMIT_ERR" }, -}; - -static bool process_non_fatal_error_v3_hw(struct hisi_hba *hisi_hba) -{ - struct device *dev = hisi_hba->dev; - const struct hisi_sas_hw_error *ras_error; - bool need_reset = false; - u32 irq_value; - int i; - - irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR0); - for (i = 0; i < ARRAY_SIZE(sas_ras_intr0_nfe); i++) { - ras_error = &sas_ras_intr0_nfe[i]; - if (ras_error->irq_msk & irq_value) { - dev_warn(dev, "SAS_RAS_INTR0: %s(irq_value=0x%x) found.\n", - ras_error->msg, irq_value); - need_reset = true; - } - } - hisi_sas_write32(hisi_hba, SAS_RAS_INTR0, irq_value); - - irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR1); - for (i = 0; i < ARRAY_SIZE(sas_ras_intr1_nfe); i++) { - ras_error = &sas_ras_intr1_nfe[i]; - if (ras_error->irq_msk & irq_value) { - dev_warn(dev, "SAS_RAS_INTR1: %s(irq_value=0x%x) found.\n", - ras_error->msg, irq_value); - need_reset = true; - } - } - hisi_sas_write32(hisi_hba, SAS_RAS_INTR1, irq_value); - - irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR2); - for (i = 0; i < ARRAY_SIZE(sas_ras_intr2_nfe); i++) { - ras_error = &sas_ras_intr2_nfe[i]; - if (ras_error->irq_msk & irq_value) { - dev_warn(dev, "SAS_RAS_INTR2: %s(irq_value=0x%x) found.\n", - ras_error->msg, irq_value); - need_reset = true; - } - } - hisi_sas_write32(hisi_hba, SAS_RAS_INTR2, irq_value); - - return need_reset; -} - -static pci_ers_result_t hisi_sas_error_detected_v3_hw(struct pci_dev *pdev, - pci_channel_state_t state) -{ - struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct hisi_hba *hisi_hba = sha->lldd_ha; - struct device *dev = hisi_hba->dev; - - dev_info(dev, "PCI error: detected callback, state(%d)!!\n", state); - if (state == pci_channel_io_perm_failure) - return PCI_ERS_RESULT_DISCONNECT; - - if (process_non_fatal_error_v3_hw(hisi_hba)) - return PCI_ERS_RESULT_NEED_RESET; - - return PCI_ERS_RESULT_CAN_RECOVER; -} - -static pci_ers_result_t hisi_sas_mmio_enabled_v3_hw(struct pci_dev *pdev) -{ - return PCI_ERS_RESULT_RECOVERED; -} - -static pci_ers_result_t hisi_sas_slot_reset_v3_hw(struct pci_dev *pdev) -{ - struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct hisi_hba *hisi_hba = sha->lldd_ha; - struct device *dev = hisi_hba->dev; - HISI_SAS_DECLARE_RST_WORK_ON_STACK(r); - - dev_info(dev, "PCI error: slot reset callback!!\n"); - queue_work(hisi_hba->wq, &r.work); - wait_for_completion(r.completion); - if (r.done) - return PCI_ERS_RESULT_RECOVERED; - - return PCI_ERS_RESULT_DISCONNECT; -} - static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev) { struct sas_ha_struct *sha = pci_get_drvdata(pdev); @@ -3171,7 +3268,7 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev) pci_power_t device_state = pdev->current_state; dev_warn(dev, "resuming from operating state [D%d]\n", - device_state); + device_state); pci_set_power_state(pdev, PCI_D0); pci_enable_wake(pdev, PCI_D0, 0); pci_restore_state(pdev); @@ -3199,9 +3296,6 @@ static const struct pci_device_id sas_v3_pci_table[] = { 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, - .mmio_enabled = hisi_sas_mmio_enabled_v3_hw, - .slot_reset = hisi_sas_slot_reset_v3_hw, .reset_prepare = hisi_sas_reset_prepare_v3_hw, .reset_done = hisi_sas_reset_done_v3_hw, }; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index eaf329db3973..ff0d8c6a8d0c 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * hosts.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995 Eric Youngdale diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f044e7d10d63..43a6b5350775 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -60,7 +60,7 @@ * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' * with an optional trailing '-' followed by a byte value (0-255). */ -#define HPSA_DRIVER_VERSION "3.4.20-125" +#define HPSA_DRIVER_VERSION "3.4.20-170" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" @@ -73,6 +73,8 @@ /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 +/* How long to wait before giving up on a command */ +#define HPSA_EH_PTRAID_TIMEOUT (240 * HZ) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); @@ -344,11 +346,6 @@ static inline bool hpsa_is_cmd_idle(struct CommandList *c) return c->scsi_cmd == SCSI_CMD_IDLE; } -static inline bool hpsa_is_pending_event(struct CommandList *c) -{ - return c->reset_pending; -} - /* extract sense key, asc, and ascq from sense data. -1 means invalid. */ static void decode_sense_data(const u8 *sense_data, int sense_data_len, u8 *sense_key, u8 *asc, u8 *ascq) @@ -1144,6 +1141,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, { dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); + if (c->device) + atomic_inc(&c->device->commands_outstanding); reply_queue = h->reply_map[raw_smp_processor_id()]; switch (c->cmd_type) { @@ -1167,9 +1166,6 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - if (unlikely(hpsa_is_pending_event(c))) - return finish_cmd(c); - __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); } @@ -1842,25 +1838,33 @@ static int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h, return count; } +#define NUM_WAIT 20 static void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) { int cmds = 0; int waits = 0; + int num_wait = NUM_WAIT; + + if (device->external) + num_wait = HPSA_EH_PTRAID_TIMEOUT; while (1) { cmds = hpsa_find_outstanding_commands_for_dev(h, device); if (cmds == 0) break; - if (++waits > 20) + if (++waits > num_wait) break; msleep(1000); } - if (waits > 20) + if (waits > num_wait) { dev_warn(&h->pdev->dev, - "%s: removing device with %d outstanding commands!\n", - __func__, cmds); + "%s: removing device [%d:%d:%d:%d] with %d outstanding commands!\n", + __func__, + h->scsi_host->host_no, + device->bus, device->target, device->lun, cmds); + } } static void hpsa_remove_device(struct ctlr_info *h, @@ -2131,11 +2135,16 @@ static int hpsa_slave_configure(struct scsi_device *sdev) sdev->no_uld_attach = !sd || !sd->expose_device; if (sd) { - if (sd->external) + sd->was_removed = 0; + if (sd->external) { queue_depth = EXTERNAL_QD; - else + sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT; + blk_queue_rq_timeout(sdev->request_queue, + HPSA_EH_PTRAID_TIMEOUT); + } else { queue_depth = sd->queue_depth != 0 ? sd->queue_depth : sdev->host->can_queue; + } } else queue_depth = sdev->host->can_queue; @@ -2146,7 +2155,12 @@ static int hpsa_slave_configure(struct scsi_device *sdev) static void hpsa_slave_destroy(struct scsi_device *sdev) { - /* nothing to do. */ + struct hpsa_scsi_dev_t *hdev = NULL; + + hdev = sdev->hostdata; + + if (hdev) + hdev->was_removed = 1; } static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h) @@ -2414,13 +2428,16 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, break; } + if (dev->in_reset) + retry = 0; + return retry; /* retry on raid path? */ } static void hpsa_cmd_resolve_events(struct ctlr_info *h, struct CommandList *c) { - bool do_wake = false; + struct hpsa_scsi_dev_t *dev = c->device; /* * Reset c->scsi_cmd here so that the reset handler will know @@ -2429,25 +2446,12 @@ static void hpsa_cmd_resolve_events(struct ctlr_info *h, */ c->scsi_cmd = SCSI_CMD_IDLE; mb(); /* Declare command idle before checking for pending events. */ - if (c->reset_pending) { - unsigned long flags; - struct hpsa_scsi_dev_t *dev; - - /* - * There appears to be a reset pending; lock the lock and - * reconfirm. If so, then decrement the count of outstanding - * commands and wake the reset command if this is the last one. - */ - spin_lock_irqsave(&h->lock, flags); - dev = c->reset_pending; /* Re-fetch under the lock. */ - if (dev && atomic_dec_and_test(&dev->reset_cmds_out)) - do_wake = true; - c->reset_pending = NULL; - spin_unlock_irqrestore(&h->lock, flags); + if (dev) { + atomic_dec(&dev->commands_outstanding); + if (dev->in_reset && + atomic_read(&dev->commands_outstanding) <= 0) + wake_up_all(&h->event_sync_wait_queue); } - - if (do_wake) - wake_up_all(&h->event_sync_wait_queue); } static void hpsa_cmd_resolve_and_free(struct ctlr_info *h, @@ -2496,6 +2500,11 @@ static void process_ioaccel2_completion(struct ctlr_info *h, dev->offload_to_be_enabled = 0; } + if (dev->in_reset) { + cmd->result = DID_RESET << 16; + return hpsa_cmd_free_and_done(h, c, cmd); + } + return hpsa_retry_cmd(h, c); } @@ -2574,6 +2583,12 @@ static void complete_scsi_command(struct CommandList *cp) cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + /* SCSI command has already been cleaned up in SML */ + if (dev->was_removed) { + hpsa_cmd_resolve_and_free(h, cp); + return; + } + if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) { if (dev->physical_device && dev->expose_device && dev->removed) { @@ -2595,10 +2610,6 @@ static void complete_scsi_command(struct CommandList *cp) return hpsa_cmd_free_and_done(h, cp, cmd); } - if ((unlikely(hpsa_is_pending_event(cp)))) - if (cp->reset_pending) - return hpsa_cmd_free_and_done(h, cp, cmd); - if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); @@ -2647,9 +2658,20 @@ static void complete_scsi_command(struct CommandList *cp) decode_sense_data(ei->SenseInfo, sense_data_size, &sense_key, &asc, &ascq); if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { - if (sense_key == ABORTED_COMMAND) { + switch (sense_key) { + case ABORTED_COMMAND: cmd->result |= DID_SOFT_ERROR << 16; break; + case UNIT_ATTENTION: + if (asc == 0x3F && ascq == 0x0E) + h->drv_req_rescan = 1; + break; + case ILLEGAL_REQUEST: + if (asc == 0x25 && ascq == 0x00) { + dev->removed = 1; + cmd->result = DID_NO_CONNECT << 16; + } + break; } break; } @@ -3037,7 +3059,7 @@ out: return rc; } -static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, +static int hpsa_send_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, u8 reset_type, int reply_queue) { int rc = IO_OK; @@ -3045,11 +3067,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct ErrorInfo *ei; c = cmd_alloc(h); - + c->device = dev; /* fill_cmd can't fail here, no data buffer to map. */ - (void) fill_cmd(c, reset_type, h, NULL, 0, 0, - scsi3addr, TYPE_MSG); + (void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG); rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); @@ -3127,9 +3148,8 @@ static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c, } static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, - unsigned char *scsi3addr, u8 reset_type, int reply_queue) + u8 reset_type, int reply_queue) { - int i; int rc = 0; /* We can really only handle one reset at a time */ @@ -3138,38 +3158,14 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, return -EINTR; } - BUG_ON(atomic_read(&dev->reset_cmds_out) != 0); - - for (i = 0; i < h->nr_cmds; i++) { - struct CommandList *c = h->cmd_pool + i; - int refcount = atomic_inc_return(&c->refcount); - - if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev, scsi3addr)) { - unsigned long flags; - - /* - * Mark the target command as having a reset pending, - * then lock a lock so that the command cannot complete - * while we're considering it. If the command is not - * idle then count it; otherwise revoke the event. - */ - c->reset_pending = dev; - spin_lock_irqsave(&h->lock, flags); /* Implied MB */ - if (!hpsa_is_cmd_idle(c)) - atomic_inc(&dev->reset_cmds_out); - else - c->reset_pending = NULL; - spin_unlock_irqrestore(&h->lock, flags); - } - - cmd_free(h, c); - } - - rc = hpsa_send_reset(h, scsi3addr, reset_type, reply_queue); - if (!rc) + rc = hpsa_send_reset(h, dev, reset_type, reply_queue); + if (!rc) { + /* incremented by sending the reset request */ + atomic_dec(&dev->commands_outstanding); wait_event(h->event_sync_wait_queue, - atomic_read(&dev->reset_cmds_out) == 0 || + atomic_read(&dev->commands_outstanding) <= 0 || lockup_detected(h)); + } if (unlikely(lockup_detected(h))) { dev_warn(&h->pdev->dev, @@ -3177,10 +3173,8 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, rc = -ENODEV; } - if (unlikely(rc)) - atomic_set(&dev->reset_cmds_out, 0); - else - rc = wait_for_device_to_become_ready(h, scsi3addr, 0); + if (!rc) + rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0); mutex_unlock(&h->reset_mutex); return rc; @@ -3956,14 +3950,18 @@ static int hpsa_update_device_info(struct ctlr_info *h, memset(this_device->device_id, 0, sizeof(this_device->device_id)); if (hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8, - sizeof(this_device->device_id)) < 0) + sizeof(this_device->device_id)) < 0) { dev_err(&h->pdev->dev, - "hpsa%d: %s: can't get device id for host %d:C0:T%d:L%d\t%s\t%.16s\n", + "hpsa%d: %s: can't get device id for [%d:%d:%d:%d]\t%s\t%.16s\n", h->ctlr, __func__, h->scsi_host->host_no, - this_device->target, this_device->lun, + this_device->bus, this_device->target, + this_device->lun, scsi_device_type(this_device->devtype), this_device->model); + rc = HPSA_LV_FAILED; + goto bail_out; + } if ((this_device->devtype == TYPE_DISK || this_device->devtype == TYPE_ZBC) && @@ -4805,6 +4803,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, c->phys_disk = dev; + if (dev->in_reset) + return -1; + return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } @@ -4925,7 +4926,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, curr_sg->reserved[0] = 0; curr_sg->reserved[1] = 0; curr_sg->reserved[2] = 0; - curr_sg->chain_indicator = 0x80; + curr_sg->chain_indicator = IOACCEL2_CHAIN; curr_sg = h->ioaccel2_cmd_sg_list[c->cmdindex]; } @@ -4942,6 +4943,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, curr_sg++; } + /* + * Set the last s/g element bit + */ + (curr_sg - 1)->chain_indicator = IOACCEL2_LAST_SG; + switch (cmd->sc_data_direction) { case DMA_TO_DEVICE: cp->direction &= ~IOACCEL2_DIRECTION_MASK; @@ -4990,6 +4996,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, } else cp->sg_count = (u8) use_sg; + if (phys_disk->in_reset) { + cmd->result = DID_RESET << 16; + return -1; + } + enqueue_cmd_and_start_io(h, c); return 0; } @@ -5007,6 +5018,9 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, if (!c->scsi_cmd->device->hostdata) return -1; + if (phys_disk->in_reset) + return -1; + /* Try to honor the device's queue depth */ if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { @@ -5090,6 +5104,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, if (!dev) return -1; + if (dev->in_reset) + return -1; + /* check for valid opcode, get LBA and block count */ switch (cmd->cmnd[0]) { case WRITE_6: @@ -5394,13 +5411,13 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, */ static int hpsa_ciss_submit(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, - unsigned char scsi3addr[]) + struct hpsa_scsi_dev_t *dev) { cmd->host_scribble = (unsigned char *) c; c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; c->Header.ReplyQueue = 0; /* unused in simple mode */ - memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); + memcpy(&c->Header.LUN.LunAddrBytes[0], &dev->scsi3addr[0], 8); c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT)); /* Fill in the request block... */ @@ -5451,6 +5468,12 @@ static int hpsa_ciss_submit(struct ctlr_info *h, hpsa_cmd_resolve_and_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } + + if (dev->in_reset) { + hpsa_cmd_resolve_and_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + enqueue_cmd_and_start_io(h, c); /* the cmd'll come back via intr handler in complete_scsi_command() */ return 0; @@ -5502,8 +5525,7 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index, } static int hpsa_ioaccel_submit(struct ctlr_info *h, - struct CommandList *c, struct scsi_cmnd *cmd, - unsigned char *scsi3addr) + struct CommandList *c, struct scsi_cmnd *cmd) { struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; int rc = IO_ACCEL_INELIGIBLE; @@ -5511,6 +5533,12 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (!dev) return SCSI_MLQUEUE_HOST_BUSY; + if (dev->in_reset) + return SCSI_MLQUEUE_HOST_BUSY; + + if (hpsa_simple_mode) + return IO_ACCEL_INELIGIBLE; + cmd->host_scribble = (unsigned char *) c; if (dev->offload_enabled) { @@ -5543,8 +5571,12 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); } - if (c->reset_pending) + + if (dev->in_reset) { + cmd->result = DID_RESET << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); + } + if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -5552,7 +5584,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) if (c2->error_data.serv_response == IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) { - rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr); + rc = hpsa_ioaccel_submit(h, c, cmd); if (rc == 0) return; if (rc == SCSI_MLQUEUE_HOST_BUSY) { @@ -5568,7 +5600,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) } } hpsa_cmd_partial_init(c->h, c->cmdindex, c); - if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { + if (hpsa_ciss_submit(c->h, c, cmd, dev)) { /* * If we get here, it means dma mapping failed. Try * again via scsi mid layer, which will then get @@ -5587,7 +5619,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; - unsigned char scsi3addr[8]; struct CommandList *c; int rc = 0; @@ -5609,14 +5640,18 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } - memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - if (unlikely(lockup_detected(h))) { cmd->result = DID_NO_CONNECT << 16; cmd->scsi_done(cmd); return 0; } + + if (dev->in_reset) + return SCSI_MLQUEUE_DEVICE_BUSY; + c = cmd_tagged_alloc(h, cmd); + if (c == NULL) + return SCSI_MLQUEUE_DEVICE_BUSY; /* * Call alternate submit routine for I/O accelerated commands. @@ -5625,7 +5660,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) if (likely(cmd->retries == 0 && !blk_rq_is_passthrough(cmd->request) && h->acciopath_status)) { - rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); + rc = hpsa_ioaccel_submit(h, c, cmd); if (rc == 0) return 0; if (rc == SCSI_MLQUEUE_HOST_BUSY) { @@ -5633,7 +5668,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; } } - return hpsa_ciss_submit(h, c, cmd, scsi3addr); + return hpsa_ciss_submit(h, c, cmd, dev); } static void hpsa_scan_complete(struct ctlr_info *h) @@ -5809,7 +5844,7 @@ static int hpsa_send_test_unit_ready(struct ctlr_info *h, /* Send the Test Unit Ready, fill_cmd can't fail, no mapping */ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD); - rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, DEFAULT_TIMEOUT); + rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) return rc; /* no unmap needed here because no data xfer. */ @@ -5915,8 +5950,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) { int rc = SUCCESS; + int i; struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; + struct hpsa_scsi_dev_t *dev = NULL; u8 reset_type; char msg[48]; unsigned long flags; @@ -5982,9 +6018,19 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical "); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); + /* + * wait to see if any commands will complete before sending reset + */ + dev->in_reset = true; /* block any new cmds from OS for this device */ + for (i = 0; i < 10; i++) { + if (atomic_read(&dev->commands_outstanding) > 0) + msleep(1000); + else + break; + } + /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type, - DEFAULT_REPLY_QUEUE); + rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE); if (rc == 0) rc = SUCCESS; else @@ -5998,6 +6044,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return_reset_status: spin_lock_irqsave(&h->reset_lock, flags); h->reset_in_progress = 0; + if (dev) + dev->in_reset = false; spin_unlock_irqrestore(&h->reset_lock, flags); return rc; } @@ -6023,7 +6071,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, BUG(); } - atomic_inc(&c->refcount); if (unlikely(!hpsa_is_cmd_idle(c))) { /* * We expect that the SCSI layer will hand us a unique tag @@ -6031,14 +6078,20 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, * two requests...because if the selected command isn't idle * then someone is going to be very disappointed. */ - dev_err(&h->pdev->dev, - "tag collision (tag=%d) in cmd_tagged_alloc().\n", - idx); - if (c->scsi_cmd != NULL) - scsi_print_command(c->scsi_cmd); - scsi_print_command(scmd); + if (idx != h->last_collision_tag) { /* Print once per tag */ + dev_warn(&h->pdev->dev, + "%s: tag collision (tag=%d)\n", __func__, idx); + if (c->scsi_cmd != NULL) + scsi_print_command(c->scsi_cmd); + if (scmd) + scsi_print_command(scmd); + h->last_collision_tag = idx; + } + return NULL; } + atomic_inc(&c->refcount); + hpsa_cmd_partial_init(h, idx, c); return c; } @@ -6106,6 +6159,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) break; /* it's ours now. */ } hpsa_cmd_partial_init(h, i, c); + c->device = NULL; return c; } @@ -6559,8 +6613,7 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd, } } -static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, - u8 reset_type) +static void hpsa_send_host_reset(struct ctlr_info *h, u8 reset_type) { struct CommandList *c; @@ -7745,7 +7798,7 @@ static void hpsa_free_pci_init(struct ctlr_info *h) hpsa_disable_interrupt_mode(h); /* pci_init 2 */ /* * call pci_disable_device before pci_release_regions per - * Documentation/PCI/pci.txt + * Documentation/PCI/pci.rst */ pci_disable_device(h->pdev); /* pci_init 1 */ pci_release_regions(h->pdev); /* pci_init 2 */ @@ -7828,7 +7881,7 @@ clean2: /* intmode+region, pci */ clean1: /* * call pci_disable_device before pci_release_regions per - * Documentation/PCI/pci.txt + * Documentation/PCI/pci.rst */ pci_disable_device(h->pdev); pci_release_regions(h->pdev); @@ -7963,10 +8016,15 @@ clean_up: static void hpsa_free_irqs(struct ctlr_info *h) { int i; + int irq_vector = 0; + + if (hpsa_simple_mode) + irq_vector = h->intr_mode; if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) { /* Single reply queue, only one irq to free */ - free_irq(pci_irq_vector(h->pdev, 0), &h->q[h->intr_mode]); + free_irq(pci_irq_vector(h->pdev, irq_vector), + &h->q[h->intr_mode]); h->q[h->intr_mode] = 0; return; } @@ -7985,6 +8043,10 @@ static int hpsa_request_irqs(struct ctlr_info *h, irqreturn_t (*intxhandler)(int, void *)) { int rc, i; + int irq_vector = 0; + + if (hpsa_simple_mode) + irq_vector = h->intr_mode; /* * initialize h->q[x] = x so that interrupt handlers know which @@ -8020,14 +8082,14 @@ static int hpsa_request_irqs(struct ctlr_info *h, if (h->msix_vectors > 0 || h->pdev->msi_enabled) { sprintf(h->intrname[0], "%s-msi%s", h->devname, h->msix_vectors ? "x" : ""); - rc = request_irq(pci_irq_vector(h->pdev, 0), + rc = request_irq(pci_irq_vector(h->pdev, irq_vector), msixhandler, 0, h->intrname[0], &h->q[h->intr_mode]); } else { sprintf(h->intrname[h->intr_mode], "%s-intx", h->devname); - rc = request_irq(pci_irq_vector(h->pdev, 0), + rc = request_irq(pci_irq_vector(h->pdev, irq_vector), intxhandler, IRQF_SHARED, h->intrname[0], &h->q[h->intr_mode]); @@ -8035,7 +8097,7 @@ static int hpsa_request_irqs(struct ctlr_info *h, } if (rc) { dev_err(&h->pdev->dev, "failed to get irq %d for %s\n", - pci_irq_vector(h->pdev, 0), h->devname); + pci_irq_vector(h->pdev, irq_vector), h->devname); hpsa_free_irqs(h); return -ENODEV; } @@ -8045,7 +8107,7 @@ static int hpsa_request_irqs(struct ctlr_info *h, static int hpsa_kdump_soft_reset(struct ctlr_info *h) { int rc; - hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER); + hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER); dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY); @@ -8101,6 +8163,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) destroy_workqueue(h->rescan_ctlr_wq); h->rescan_ctlr_wq = NULL; } + if (h->monitor_ctlr_wq) { + destroy_workqueue(h->monitor_ctlr_wq); + h->monitor_ctlr_wq = NULL; + } + kfree(h); /* init_one 1 */ } @@ -8436,8 +8503,8 @@ static void hpsa_event_monitor_worker(struct work_struct *work) spin_lock_irqsave(&h->lock, flags); if (!h->remove_in_progress) - schedule_delayed_work(&h->event_monitor_work, - HPSA_EVENT_MONITOR_INTERVAL); + queue_delayed_work(h->monitor_ctlr_wq, &h->event_monitor_work, + HPSA_EVENT_MONITOR_INTERVAL); spin_unlock_irqrestore(&h->lock, flags); } @@ -8482,7 +8549,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) spin_lock_irqsave(&h->lock, flags); if (!h->remove_in_progress) - schedule_delayed_work(&h->monitor_ctlr_work, + queue_delayed_work(h->monitor_ctlr_wq, &h->monitor_ctlr_work, h->heartbeat_sample_interval); spin_unlock_irqrestore(&h->lock, flags); } @@ -8650,6 +8717,12 @@ reinit_after_soft_reset: goto clean7; /* aer/h */ } + h->monitor_ctlr_wq = hpsa_create_controller_wq(h, "monitor"); + if (!h->monitor_ctlr_wq) { + rc = -ENOMEM; + goto clean7; + } + /* * At this point, the controller is ready to take commands. * Now, if reset_devices and the hard reset didn't work, try @@ -8779,6 +8852,10 @@ clean1: /* wq/aer/h */ destroy_workqueue(h->rescan_ctlr_wq); h->rescan_ctlr_wq = NULL; } + if (h->monitor_ctlr_wq) { + destroy_workqueue(h->monitor_ctlr_wq); + h->monitor_ctlr_wq = NULL; + } kfree(h); return rc; } @@ -8926,6 +9003,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&h->event_monitor_work); destroy_workqueue(h->rescan_ctlr_wq); destroy_workqueue(h->resubmit_wq); + destroy_workqueue(h->monitor_ctlr_wq); hpsa_delete_sas_host(h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 59e023696fff..f8c88fc7b80a 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -65,6 +65,7 @@ struct hpsa_scsi_dev_t { u8 physical_device : 1; u8 expose_device; u8 removed : 1; /* device is marked for death */ + u8 was_removed : 1; /* device actually removed */ #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" unsigned char device_id[16]; /* from inquiry pg. 0x83 */ u64 sas_address; @@ -75,11 +76,12 @@ struct hpsa_scsi_dev_t { unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ u16 queue_depth; /* max queue_depth for this device */ - atomic_t reset_cmds_out; /* Count of commands to-be affected */ + atomic_t commands_outstanding; /* track commands sent to device */ atomic_t ioaccel_cmds_out; /* Only used for physical devices * counts commands sent to physical * device via "ioaccel" path. */ + bool in_reset; u32 ioaccel_handle; u8 active_path_index; u8 path_map; @@ -174,6 +176,7 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; + int last_collision_tag; /* tags are global */ atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 @@ -300,6 +303,7 @@ struct ctlr_info { int needs_abort_tags_swizzled; struct workqueue_struct *resubmit_wq; struct workqueue_struct *rescan_ctlr_wq; + struct workqueue_struct *monitor_ctlr_wq; atomic_t abort_cmds_available; wait_queue_head_t event_sync_wait_queue; struct mutex reset_mutex; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 21a726e2eec6..7825cbfea4dc 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -448,7 +448,7 @@ struct CommandList { struct hpsa_scsi_dev_t *phys_disk; int abort_pending; - struct hpsa_scsi_dev_t *reset_pending; + struct hpsa_scsi_dev_t *device; atomic_t refcount; /* Must be last to avoid memset in hpsa_cmd_init() */ } __aligned(COMMANDLIST_ALIGNMENT); @@ -517,6 +517,7 @@ struct ioaccel2_sg_element { u8 reserved[3]; u8 chain_indicator; #define IOACCEL2_CHAIN 0x80 +#define IOACCEL2_LAST_SG 0x40 }; /* diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 251c084a6ff0..6a2561f26e38 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HighPoint RR3xxx/4xxx controller driver for Linux * Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved. * - * 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; version 2 of the License. - * - * 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. - * * Please report bugs/comments/suggestions to linux@highpoint-tech.com * * For more information, visit http://www.highpoint-tech.com diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h index 4d1c51153b70..35184c2008af 100644 --- a/drivers/scsi/hptiop.h +++ b/drivers/scsi/hptiop.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * HighPoint RR3xxx/4xxx controller driver for Linux * Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved. * - * 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; version 2 of the License. - * - * 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. - * * Please report bugs/comments/suggestions to linux@highpoint-tech.com * * For more information, visit http://www.highpoint-tech.com diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index 3840c64f2966..5eb1cb1a0028 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -1,2 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi.o obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 3ad997ac3510..acd16e0d52cf 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1,24 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter * * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) IBM Corporation, 2008 - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/module.h> diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 459cc288ba1d..7da89f4d26b2 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -1,24 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter * * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation * * Copyright (C) IBM Corporation, 2008 - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _IBMVFC_H diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 8cec5230fe31..7f66a7783209 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* ------------------------------------------------------------ * ibmvscsi.c * (C) Copyright IBM Corporation 1994, 2004 @@ -5,21 +6,6 @@ * Santiago Leon (santil@us.ibm.com) * Dave Boutcher (sleddog@us.ibm.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * * ------------------------------------------------------------ * Emulation of a SCSI host adapter for Virtual I/O devices * @@ -828,7 +814,7 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) atomic_set(&hostdata->request_limit, 0); purge_requests(hostdata, DID_ERROR); - hostdata->reset_crq = 1; + hostdata->action = IBMVSCSI_HOST_ACTION_RESET; wake_up(&hostdata->work_wait_q); } @@ -1179,7 +1165,8 @@ static void login_rsp(struct srp_event_struct *evt_struct) be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta)); /* If we had any pending I/Os, kick them */ - scsi_unblock_requests(hostdata->host); + hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK; + wake_up(&hostdata->work_wait_q); } /** @@ -1797,7 +1784,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, /* We need to re-setup the interpartition connection */ dev_info(hostdata->dev, "Re-enabling adapter!\n"); hostdata->client_migrated = 1; - hostdata->reenable_crq = 1; + hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE; purge_requests(hostdata, DID_REQUEUE); wake_up(&hostdata->work_wait_q); } else { @@ -2050,6 +2037,16 @@ static struct device_attribute ibmvscsi_host_config = { .show = show_host_config, }; +static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type) +{ + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + + dev_info(hostdata->dev, "Initiating adapter reset!\n"); + ibmvscsi_reset_host(hostdata); + + return 0; +} + static struct device_attribute *ibmvscsi_attrs[] = { &ibmvscsi_host_vhost_loc, &ibmvscsi_host_vhost_name, @@ -2076,6 +2073,7 @@ static struct scsi_host_template driver_template = { .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler, .slave_configure = ibmvscsi_slave_configure, .change_queue_depth = ibmvscsi_change_queue_depth, + .host_reset = ibmvscsi_host_reset, .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT, .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT, .this_id = -1, @@ -2105,48 +2103,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) { + unsigned long flags; int rc; char *action = "reset"; - if (hostdata->reset_crq) { - smp_rmb(); - hostdata->reset_crq = 0; - + spin_lock_irqsave(hostdata->host->host_lock, flags); + switch (hostdata->action) { + case IBMVSCSI_HOST_ACTION_UNBLOCK: + rc = 0; + break; + case IBMVSCSI_HOST_ACTION_RESET: + spin_unlock_irqrestore(hostdata->host->host_lock, flags); rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + spin_lock_irqsave(hostdata->host->host_lock, flags); if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); vio_enable_interrupts(to_vio_dev(hostdata->dev)); - } else if (hostdata->reenable_crq) { - smp_rmb(); + break; + case IBMVSCSI_HOST_ACTION_REENABLE: action = "enable"; + spin_unlock_irqrestore(hostdata->host->host_lock, flags); rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata); - hostdata->reenable_crq = 0; + spin_lock_irqsave(hostdata->host->host_lock, flags); if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); - } else + break; + case IBMVSCSI_HOST_ACTION_NONE: + default: + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return; + } + + hostdata->action = IBMVSCSI_HOST_ACTION_NONE; if (rc) { atomic_set(&hostdata->request_limit, -1); dev_err(hostdata->dev, "error after %s\n", action); } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); scsi_unblock_requests(hostdata->host); } -static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) { if (kthread_should_stop()) return 1; - else if (hostdata->reset_crq) { - smp_rmb(); - return 1; - } else if (hostdata->reenable_crq) { - smp_rmb(); - return 1; + switch (hostdata->action) { + case IBMVSCSI_HOST_ACTION_NONE: + return 0; + case IBMVSCSI_HOST_ACTION_RESET: + case IBMVSCSI_HOST_ACTION_REENABLE: + case IBMVSCSI_HOST_ACTION_UNBLOCK: + default: + break; } - return 0; + return 1; +} + +static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(hostdata->host->host_lock, flags); + rc = __ibmvscsi_work_to_do(hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + + return rc; } static int ibmvscsi_work(void *data) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 3a7875575616..e60916ef7a49 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* ------------------------------------------------------------ * ibmvscsi.h * (C) Copyright IBM Corporation 1994, 2003 @@ -5,21 +6,6 @@ * Santiago Leon (santil@us.ibm.com) * Dave Boutcher (sleddog@us.ibm.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * * ------------------------------------------------------------ * Emulation of a SCSI host adapter for Virtual I/O devices * @@ -88,13 +74,19 @@ struct event_pool { dma_addr_t iu_token; }; +enum ibmvscsi_host_action { + IBMVSCSI_HOST_ACTION_NONE = 0, + IBMVSCSI_HOST_ACTION_RESET, + IBMVSCSI_HOST_ACTION_REENABLE, + IBMVSCSI_HOST_ACTION_UNBLOCK, +}; + /* all driver data associated with a host adapter */ struct ibmvscsi_host_data { struct list_head host_list; atomic_t request_limit; int client_migrated; - int reset_crq; - int reenable_crq; + enum ibmvscsi_host_action action; struct device *dev; struct event_pool pool; struct crq_queue queue; diff --git a/drivers/scsi/ibmvscsi_tgt/Makefile b/drivers/scsi/ibmvscsi_tgt/Makefile index 0c060ce64cb0..cc7a8256dcf8 100644 --- a/drivers/scsi/ibmvscsi_tgt/Makefile +++ b/drivers/scsi/ibmvscsi_tgt/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsis.o ibmvscsis-y := libsrp.o ibmvscsi_tgt.o diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 7ca277e28d63..7f9535392a93 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * IBM Virtual SCSI Target Driver * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp. @@ -10,16 +11,6 @@ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com> * Authors: Michael Cyr <mikecyr@linux.vnet.ibm.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 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. - * ****************************************************************************/ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h index cc96c2731134..7ae074e5d7a1 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /******************************************************************************* * IBM Virtual SCSI Target Driver * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp. @@ -11,16 +12,6 @@ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com> * Authors: Michael Cyr <mikecyr@linux.vnet.ibm.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 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. - * ****************************************************************************/ #ifndef __H_IBMVSCSI_TGT diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.c b/drivers/scsi/ibmvscsi_tgt/libsrp.c index 5a4cc28ca5ff..8a0e28aec928 100644 --- a/drivers/scsi/ibmvscsi_tgt/libsrp.c +++ b/drivers/scsi/ibmvscsi_tgt/libsrp.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * SCSI RDMA Protocol lib functions * * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org> * Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM Corp. * - * 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. - * ***********************************************************************/ #define pr_fmt(fmt) "libsrp: " fmt diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index cea7f502e8ca..2519fb7aee51 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* imm.c -- low level driver for the IOMEGA MatchMaker * parallel port SCSI host adapter. * @@ -686,7 +687,7 @@ static int imm_completion(struct scsi_cmnd *cmd) if (cmd->SCp.buffer && !cmd->SCp.this_residual) { /* if scatter/gather, advance to the next segment */ if (cmd->SCp.buffers_residual--) { - cmd->SCp.buffer++; + cmd->SCp.buffer = sg_next(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); @@ -796,21 +797,21 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) return 0; } return 1; /* wait until imm_wakeup claims parport */ - /* Phase 1 - Connected */ - case 1: + + case 1: /* Phase 1 - Connected */ imm_connect(dev, CONNECT_EPP_MAYBE); cmd->SCp.phase++; + /* fall through */ - /* Phase 2 - We are now talking to the scsi bus */ - case 2: + case 2: /* Phase 2 - We are now talking to the scsi bus */ if (!imm_select(dev, scmd_id(cmd))) { imm_fail(dev, DID_NO_CONNECT); return 0; } cmd->SCp.phase++; + /* fall through */ - /* Phase 3 - Ready to accept a command */ - case 3: + case 3: /* Phase 3 - Ready to accept a command */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return 1; @@ -818,9 +819,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) if (!imm_send_command(cmd)) return 0; cmd->SCp.phase++; + /* fall through */ - /* Phase 4 - Setup scatter/gather buffers */ - case 4: + case 4: /* Phase 4 - Setup scatter/gather buffers */ if (scsi_bufflen(cmd)) { cmd->SCp.buffer = scsi_sglist(cmd); cmd->SCp.this_residual = cmd->SCp.buffer->length; @@ -834,8 +835,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) cmd->SCp.phase++; if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; - /* Phase 5 - Pre-Data transfer stage */ - case 5: + /* fall through */ + + case 5: /* Phase 5 - Pre-Data transfer stage */ /* Spin lock for BUSY */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) @@ -850,9 +852,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) if (imm_negotiate(dev)) return 0; cmd->SCp.phase++; + /* fall through */ - /* Phase 6 - Data transfer stage */ - case 6: + case 6: /* Phase 6 - Data transfer stage */ /* Spin lock for BUSY */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) @@ -866,9 +868,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) return 1; } cmd->SCp.phase++; + /* fall through */ - /* Phase 7 - Post data transfer stage */ - case 7: + case 7: /* Phase 7 - Post data transfer stage */ if ((dev->dp) && (dev->rd)) { if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) { w_ctr(ppb, 0x4); @@ -878,9 +880,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) } } cmd->SCp.phase++; + /* fall through */ - /* Phase 8 - Read status/message */ - case 8: + case 8: /* Phase 8 - Read status/message */ /* Check for data overrun */ if (imm_wait(dev) != (unsigned char) 0xb8) { imm_fail(dev, DID_ERROR); diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index eb2778b5c81b..41fd64c9c8e9 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /************************************************************************** * Initio 9100 device driver for Linux. * @@ -6,21 +7,6 @@ * Copyright (c) 2004 Christoph Hellwig <hch@lst.de> * Copyright (c) 2007 Red Hat * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ************************************************************************* * * DESCRIPTION: diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 6d053e220153..079c04bc448a 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1,24 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * ipr.c -- driver for IBM Power Linux RAID adapters * * Written By: Brian King <brking@us.ibm.com>, IBM Corporation * * Copyright (C) 2003, 2004 IBM Corporation - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ /* @@ -3915,22 +3901,23 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, u8 *buffer, u32 len) { int bsize_elem, i, result = 0; - struct scatterlist *scatterlist; + struct scatterlist *sg; void *kaddr; /* Determine the actual number of bytes per element */ bsize_elem = PAGE_SIZE * (1 << sglist->order); - scatterlist = sglist->scatterlist; + sg = sglist->scatterlist; - for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), + buffer += bsize_elem) { + struct page *page = sg_page(sg); kaddr = kmap(page); memcpy(kaddr, buffer, bsize_elem); kunmap(page); - scatterlist[i].length = bsize_elem; + sg->length = bsize_elem; if (result != 0) { ipr_trace; @@ -3939,13 +3926,13 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, } if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + struct page *page = sg_page(sg); kaddr = kmap(page); memcpy(kaddr, buffer, len % bsize_elem); kunmap(page); - scatterlist[i].length = len % bsize_elem; + sg->length = len % bsize_elem; } sglist->buffer_len = len; @@ -3966,6 +3953,7 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd, struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64; struct scatterlist *scatterlist = sglist->scatterlist; + struct scatterlist *sg; int i; ipr_cmd->dma_use_sg = sglist->num_dma_sg; @@ -3974,10 +3962,10 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd, ioarcb->ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg); - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { + for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) { ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE); - ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i])); - ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i])); + ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg)); + ioadl64[i].address = cpu_to_be64(sg_dma_address(sg)); } ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); @@ -3997,6 +3985,7 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd, struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; struct scatterlist *scatterlist = sglist->scatterlist; + struct scatterlist *sg; int i; ipr_cmd->dma_use_sg = sglist->num_dma_sg; @@ -4006,11 +3995,11 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd, ioarcb->ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { + for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) { ioadl[i].flags_and_data_len = - cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i])); + cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(sg)); ioadl[i].address = - cpu_to_be32(sg_dma_address(&scatterlist[i])); + cpu_to_be32(sg_dma_address(sg)); } ioadl[i-1].flags_and_data_len |= diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index f6baa2351313..a67baeb36d1f 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * ipr.h -- driver for IBM Power Linux RAID adapters * @@ -5,20 +6,6 @@ * * Copyright (C) 2003, 2004 IBM Corporation * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * Alan Cox <alan@lxorguk.ukuu.org.uk> - Removed several careless u32/dma_addr_t errors * that broke 64bit platforms. */ diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 9d29edb9f590..49aa4e657c44 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -1087,7 +1087,7 @@ static void sci_remote_device_ready_state_enter(struct sci_base_state_machine *s if (dev->dev_type == SAS_SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) { sci_change_state(&idev->sm, SCI_STP_DEV_IDLE); - } else if (dev_is_expander(dev)) { + } else if (dev_is_expander(dev->dev_type)) { sci_change_state(&idev->sm, SCI_SMP_DEV_IDLE); } else isci_remote_device_ready(ihost, idev); @@ -1478,7 +1478,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, struct domain_device *dev = idev->domain_dev; enum sci_status status; - if (dev->parent && dev_is_expander(dev->parent)) + if (dev->parent && dev_is_expander(dev->parent->dev_type)) status = sci_remote_device_ea_construct(iport, idev); else status = sci_remote_device_da_construct(iport, idev); diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index 47a013fffae7..3ad681c4c20a 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h @@ -295,11 +295,6 @@ static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_conte return idev; } -static inline bool dev_is_expander(struct domain_device *dev) -{ - return dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE; -} - static inline void sci_remote_device_decrement_request_count(struct isci_remote_device *idev) { /* XXX delete this voodoo when converting to the top-level device diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 1b18cf55167e..343d24c7e788 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -224,7 +224,7 @@ static void scu_ssp_request_construct_task_context( idev = ireq->target_device; iport = idev->owning_port; - /* Fill in the TC with the its required data */ + /* Fill in the TC with its required data */ task_context->abort = 0; task_context->priority = 0; task_context->initiator_request = 1; @@ -506,7 +506,7 @@ static void scu_sata_request_construct_task_context( idev = ireq->target_device; iport = idev->owning_port; - /* Fill in the TC with the its required data */ + /* Fill in the TC with its required data */ task_context->abort = 0; task_context->priority = SCU_TASK_PRIORITY_NORMAL; task_context->initiator_request = 1; @@ -3101,7 +3101,7 @@ sci_io_request_construct(struct isci_host *ihost, /* pass */; else if (dev_is_sata(dev)) memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd)); - else if (dev_is_expander(dev)) + else if (dev_is_expander(dev->dev_type)) /* pass */; else return SCI_FAILURE_UNSUPPORTED_PROTOCOL; @@ -3235,7 +3235,7 @@ sci_io_request_construct_smp(struct device *dev, iport = idev->owning_port; /* - * Fill in the TC with the its required data + * Fill in the TC with its required data * 00h */ task_context->priority = 0; diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index fb6eba331ac6..26fa1a4d1e6b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -511,7 +511,7 @@ int isci_task_abort_task(struct sas_task *task) "%s: dev = %p (%s%s), task = %p, old_request == %p\n", __func__, idev, (dev_is_sata(task->dev) ? "STP/SATA" - : ((dev_is_expander(task->dev)) + : ((dev_is_expander(task->dev->dev_type)) ? "SMP" : "SSP")), ((idev) ? ((test_bit(IDEV_GONE, &idev->flags)) diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index d453667612f8..e4857b728033 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Export the iSCSI boot info to userland via sysfs. * * Copyright (C) 2010 Red Hat, Inc. All rights reserved. * Copyright (C) 2010 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation - * - * 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> diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ed3debce2819..7bedbe877704 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * iSCSI Initiator over TCP/IP Data-Path * @@ -7,16 +8,6 @@ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * maintained by open-iscsi@googlegroups.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 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. - * * See the file COPYING included with this distribution for more details. * * Credits: diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 06d42d00a323..791453195099 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * iSCSI Initiator TCP Transport * Copyright (C) 2004 Dmitry Yusupov @@ -6,16 +7,6 @@ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * maintained by open-iscsi@googlegroups.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 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. - * * See the file COPYING included with this distribution for more details. */ diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 1ad28262b00a..7f683e42c798 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* jazz_esp.c: ESP front-end for MIPS JAZZ systems. * * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index dc839279bbd9..abac2f350aee 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -*- mode: c; c-basic-offset: 8 -*- */ /* PARISC LASI driver for the 53c700 chip @@ -5,19 +6,6 @@ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.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 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 program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- */ diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index f969a71348ef..9c5f7c9178c6 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 6384a98048af..13a2e7c33cb1 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2008 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 42bcf7f3a0f9..8e1053bdd843 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 Intel Corporation. All rights reserved. * Copyright(c) 2008 Red Hat, Inc. All rights reserved. * Copyright(c) 2008 Mike Christie * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index b1bd283be51c..bf2cc9656e19 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 Intel Corporation. All rights reserved. * Copyright(c) 2008 Red Hat, Inc. All rights reserved. * Copyright(c) 2008 Mike Christie * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c index 0382ac06906e..f3aefb2deca9 100644 --- a/drivers/scsi/libfc/fc_frame.c +++ b/drivers/scsi/libfc/fc_frame.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index dbadbc81b24b..19c4ab4e0f4d 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2009 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h index b74189d89322..685e3bdd033a 100644 --- a/drivers/scsi/libfc/fc_libfc.h +++ b/drivers/scsi/libfc/fc_libfc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright(c) 2009 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index ff943f477d6f..684c5e361a28 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c index c168321b560e..c045898b84df 100644 --- a/drivers/scsi/libfc/fc_npiv.c +++ b/drivers/scsi/libfc/fc_npiv.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2009 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 5bf61431434b..e0f3852fdad1 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index e893949a3d11..ebd47c0cf9e9 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * iSCSI lib functions * @@ -6,20 +7,6 @@ * Copyright (C) 2004 - 2005 Dmitry Yusupov * Copyright (C) 2004 - 2005 Alex Aizman * maintained by open-iscsi@googlegroups.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/types.h> #include <linux/kfifo.h> diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index c3fe3f3a78f5..6ef93c7af954 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * iSCSI over TCP/IP Data-Path lib * @@ -7,18 +8,6 @@ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * maintained by open-iscsi@googlegroups.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 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. - * - * See the file COPYING included with this distribution for more details. - * * Credits: * Christoph Hellwig * FUJITA Tomonori diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig index 13739bfacc67..5c6a5eff2f8e 100644 --- a/drivers/scsi/libsas/Kconfig +++ b/drivers/scsi/libsas/Kconfig @@ -1,26 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Kernel configuration file for the SAS Class # # Copyright (C) 2005 Adaptec, Inc. All rights reserved. # Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> # -# This file is licensed under GPLv2. -# -# 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; version 2 of the -# License. -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# config SCSI_SAS_LIBSAS tristate "SAS Domain Transport Attributes" diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile index 5d51520c6f23..e63a54f5ab8c 100644 --- a/drivers/scsi/libsas/Makefile +++ b/drivers/scsi/libsas/Makefile @@ -1,25 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Kernel Makefile for the libsas helpers # # Copyright (C) 2005 Adaptec, Inc. All rights reserved. # Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> # -# This file is licensed under GPLv2. -# -# 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; version 2 of the -# License. -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o libsas-y += sas_init.o \ diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 6f93fee2b21b..e9e00740f7ca 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -1,24 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Support for SATA devices on Serial Attached SCSI (SAS) controllers * * Copyright (C) 2006 IBM Corporation * * Written by: Darrick J. Wong <djwong@us.ibm.com>, IBM Corporation - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include <linux/scatterlist.h> @@ -281,7 +267,7 @@ int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) res = sas_get_report_phy_sata(dev->parent, phy->phy_id, &dev->sata_dev.rps_resp); if (res) { - pr_debug("report phy sata to %016llx:0x%x returned 0x%x\n", + pr_debug("report phy sata to %016llx:%02d returned 0x%x\n", SAS_ADDR(dev->parent->sas_addr), phy->phy_id, res); return res; diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 726ada9b8c79..abcad097ff2f 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Discover process * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/scatterlist.h> @@ -309,7 +293,7 @@ void sas_free_device(struct kref *kref) dev->phy = NULL; /* remove the phys and ports, everything else should be gone */ - if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(dev->dev_type)) kfree(dev->ex_dev.ex_phy); if (dev_is_sata(dev) && dev->sata_dev.ap) { @@ -519,8 +503,7 @@ static void sas_revalidate_domain(struct work_struct *work) pr_debug("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, task_pid_nr(current)); - if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE || - ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE)) + if (ddev && dev_is_expander(ddev->dev_type)) res = sas_ex_revalidate_domain(ddev); pr_debug("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index b1e0f7d2b396..a1852f6c042b 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Event processing * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/export.h> diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 17b45a0c7bc3..9fdb9c9fbda4 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Expander discovery and configuration * @@ -5,21 +6,6 @@ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/scatterlist.h> @@ -826,9 +812,14 @@ static struct domain_device *sas_ex_discover_end_dev( #ifdef CONFIG_SCSI_SAS_ATA if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { if (child->linkrate > parent->min_linkrate) { + struct sas_phy *cphy = child->phy; + enum sas_linkrate min_prate = cphy->minimum_linkrate, + parent_min_lrate = parent->min_linkrate, + min_linkrate = (min_prate > parent_min_lrate) ? + parent_min_lrate : 0; struct sas_phy_linkrates rates = { .maximum_linkrate = parent->min_linkrate, - .minimum_linkrate = parent->min_linkrate, + .minimum_linkrate = min_linkrate, }; int ret; @@ -865,7 +856,7 @@ static struct domain_device *sas_ex_discover_end_dev( res = sas_discover_sata(child); if (res) { - pr_notice("sas_discover_sata() for device %16llx at %016llx:0x%x returned 0x%x\n", + pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); goto out_list_del; @@ -890,7 +881,7 @@ static struct domain_device *sas_ex_discover_end_dev( res = sas_discover_end_dev(child); if (res) { - pr_notice("sas_discover_end_dev() for device %16llx at %016llx:0x%x returned 0x%x\n", + pr_notice("sas_discover_end_dev() for device %16llx at %016llx:%02d returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); goto out_list_del; @@ -955,7 +946,7 @@ static struct domain_device *sas_ex_discover_expander( int res; if (phy->routing_attr == DIRECT_ROUTING) { - pr_warn("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not allowed\n", + pr_warn("ex %016llx:%02d:D <--> ex %016llx:0x%x is not allowed\n", SAS_ADDR(parent->sas_addr), phy_id, SAS_ADDR(phy->attached_sas_addr), phy->attached_phy_id); @@ -1014,6 +1005,8 @@ static struct domain_device *sas_ex_discover_expander( list_del(&child->dev_list_node); spin_unlock_irq(&parent->port->dev_list_lock); sas_put_device(child); + sas_port_delete(phy->port); + phy->port = NULL; return NULL; } list_add_tail(&child->siblings, &parent->ex_dev.children); @@ -1065,7 +1058,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) ex_phy->attached_dev_type != SAS_FANOUT_EXPANDER_DEVICE && ex_phy->attached_dev_type != SAS_EDGE_EXPANDER_DEVICE && ex_phy->attached_dev_type != SAS_SATA_PENDING) { - pr_warn("unknown device type(0x%x) attached to ex %016llx phy 0x%x\n", + pr_warn("unknown device type(0x%x) attached to ex %016llx phy%02d\n", ex_phy->attached_dev_type, SAS_ADDR(dev->sas_addr), phy_id); @@ -1081,7 +1074,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) } if (sas_ex_join_wide_port(dev, phy_id)) { - pr_debug("Attaching ex phy%d to wide port %016llx\n", + pr_debug("Attaching ex phy%02d to wide port %016llx\n", phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); return res; } @@ -1093,13 +1086,13 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) break; case SAS_FANOUT_EXPANDER_DEVICE: if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) { - pr_debug("second fanout expander %016llx phy 0x%x attached to ex %016llx phy 0x%x\n", + pr_debug("second fanout expander %016llx phy%02d attached to ex %016llx phy%02d\n", SAS_ADDR(ex_phy->attached_sas_addr), ex_phy->attached_phy_id, SAS_ADDR(dev->sas_addr), phy_id); sas_ex_disable_phy(dev, phy_id); - break; + return res; } else memcpy(dev->port->disc.fanout_sas_addr, ex_phy->attached_sas_addr, SAS_ADDR_SIZE); @@ -1111,27 +1104,9 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) break; } - if (child) { - int i; - - for (i = 0; i < ex->num_phys; i++) { - if (ex->ex_phy[i].phy_state == PHY_VACANT || - ex->ex_phy[i].phy_state == PHY_NOT_PRESENT) - continue; - /* - * Due to races, the phy might not get added to the - * wide port, so we add the phy to the wide port here. - */ - if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == - SAS_ADDR(child->sas_addr)) { - ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; - if (sas_ex_join_wide_port(dev, i)) - pr_debug("Attaching ex phy%d to wide port %016llx\n", - i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); - } - } - } - + if (!child) + pr_notice("ex %016llx phy%02d failed to discover\n", + SAS_ADDR(dev->sas_addr), phy_id); return res; } @@ -1147,11 +1122,10 @@ static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr) phy->phy_state == PHY_NOT_PRESENT) continue; - if ((phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE || - phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE) && + if (dev_is_expander(phy->attached_dev_type) && phy->routing_attr == SUBTRACTIVE_ROUTING) { - memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE); + memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); return 1; } @@ -1163,17 +1137,16 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev) { struct expander_device *ex = &dev->ex_dev; struct domain_device *child; - u8 sub_addr[8] = {0, }; + u8 sub_addr[SAS_ADDR_SIZE] = {0, }; list_for_each_entry(child, &ex->children, siblings) { - if (child->dev_type != SAS_EDGE_EXPANDER_DEVICE && - child->dev_type != SAS_FANOUT_EXPANDER_DEVICE) + if (!dev_is_expander(child->dev_type)) continue; if (sub_addr[0] == 0) { sas_find_sub_addr(child, sub_addr); continue; } else { - u8 s2[8]; + u8 s2[SAS_ADDR_SIZE]; if (sas_find_sub_addr(child, s2) && (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) { @@ -1252,8 +1225,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev) phy->phy_state == PHY_NOT_PRESENT) continue; - if ((phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE || - phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE) && + if (dev_is_expander(phy->attached_dev_type) && phy->routing_attr == SUBTRACTIVE_ROUTING) { if (!sub_sas_addr) @@ -1261,7 +1233,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev) else if (SAS_ADDR(sub_sas_addr) != SAS_ADDR(phy->attached_sas_addr)) { - pr_notice("ex %016llx phy 0x%x diverges(%016llx) on subtractive boundary(%016llx). Disabled\n", + pr_notice("ex %016llx phy%02d diverges(%016llx) on subtractive boundary(%016llx). Disabled\n", SAS_ADDR(dev->sas_addr), i, SAS_ADDR(phy->attached_sas_addr), SAS_ADDR(sub_sas_addr)); @@ -1282,7 +1254,7 @@ static void sas_print_parent_topology_bug(struct domain_device *child, }; struct domain_device *parent = child->parent; - pr_notice("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x has %c:%c routing link!\n", + pr_notice("%s ex %016llx phy%02d <--> %s ex %016llx phy%02d has %c:%c routing link!\n", ex_type[parent->dev_type], SAS_ADDR(parent->sas_addr), parent_phy->phy_id, @@ -1304,7 +1276,7 @@ static int sas_check_eeds(struct domain_device *child, if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) { res = -ENODEV; - pr_warn("edge ex %016llx phy S:0x%x <--> edge ex %016llx phy S:0x%x, while there is a fanout ex %016llx\n", + pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n", SAS_ADDR(parent->sas_addr), parent_phy->phy_id, SAS_ADDR(child->sas_addr), @@ -1327,7 +1299,7 @@ static int sas_check_eeds(struct domain_device *child, ; else { res = -ENODEV; - pr_warn("edge ex %016llx phy 0x%x <--> edge ex %016llx phy 0x%x link forms a third EEDS!\n", + pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n", SAS_ADDR(parent->sas_addr), parent_phy->phy_id, SAS_ADDR(child->sas_addr), @@ -1349,8 +1321,7 @@ static int sas_check_parent_topology(struct domain_device *child) if (!child->parent) return 0; - if (child->parent->dev_type != SAS_EDGE_EXPANDER_DEVICE && - child->parent->dev_type != SAS_FANOUT_EXPANDER_DEVICE) + if (!dev_is_expander(child->parent->dev_type)) return 0; parent_ex = &child->parent->ex_dev; @@ -1445,11 +1416,11 @@ static int sas_configure_present(struct domain_device *dev, int phy_id, goto out; res = rri_resp[2]; if (res == SMP_RESP_NO_INDEX) { - pr_warn("overflow of indexes: dev %016llx phy 0x%x index 0x%x\n", + pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n", SAS_ADDR(dev->sas_addr), phy_id, i); goto out; } else if (res != SMP_RESP_FUNC_ACC) { - pr_notice("%s: dev %016llx phy 0x%x index 0x%x result 0x%x\n", + pr_notice("%s: dev %016llx phy%02d index 0x%x result 0x%x\n", __func__, SAS_ADDR(dev->sas_addr), phy_id, i, res); goto out; @@ -1515,7 +1486,7 @@ static int sas_configure_set(struct domain_device *dev, int phy_id, goto out; res = cri_resp[2]; if (res == SMP_RESP_NO_INDEX) { - pr_warn("overflow of indexes: dev %016llx phy 0x%x index 0x%x\n", + pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n", SAS_ADDR(dev->sas_addr), phy_id, index); } out: @@ -1646,8 +1617,7 @@ static int sas_ex_level_discovery(struct asd_sas_port *port, const int level) struct domain_device *dev; list_for_each_entry(dev, &port->dev_list, dev_list_node) { - if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || - dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(dev->dev_type)) { struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); @@ -1760,10 +1730,11 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, res = sas_get_phy_discover(dev, phy_id, disc_resp); if (res == 0) { - memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8); + memcpy(sas_addr, disc_resp->disc.attached_sas_addr, + SAS_ADDR_SIZE); *type = to_dev_type(dr); if (*type == 0) - memset(sas_addr, 0, 8); + memset(sas_addr, 0, SAS_ADDR_SIZE); } kfree(disc_resp); return res; @@ -1870,13 +1841,15 @@ static int sas_find_bcast_dev(struct domain_device *dev, if (phy_id != -1) { *src_dev = dev; ex->ex_change_count = ex_change_count; - pr_info("Expander phy change count has changed\n"); + pr_info("ex %016llx phy%02d change count has changed\n", + SAS_ADDR(dev->sas_addr), phy_id); return res; } else - pr_info("Expander phys DID NOT change\n"); + pr_info("ex %016llx phys DID NOT change\n", + SAS_ADDR(dev->sas_addr)); } list_for_each_entry(ch, &ex->children, siblings) { - if (ch->dev_type == SAS_EDGE_EXPANDER_DEVICE || ch->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(ch->dev_type)) { res = sas_find_bcast_dev(ch, src_dev); if (*src_dev) return res; @@ -1893,8 +1866,7 @@ static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_devi list_for_each_entry_safe(child, n, &ex->children, siblings) { set_bit(SAS_DEV_GONE, &child->state); - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(child->dev_type)) sas_unregister_ex_tree(port, child); else sas_unregister_dev(port, child); @@ -1914,8 +1886,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent, if (SAS_ADDR(child->sas_addr) == SAS_ADDR(phy->attached_sas_addr)) { set_bit(SAS_DEV_GONE, &child->state); - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(child->dev_type)) sas_unregister_ex_tree(parent->port, child); else sas_unregister_dev(parent->port, child); @@ -1944,8 +1915,7 @@ static int sas_discover_bfs_by_root_level(struct domain_device *root, int res = 0; list_for_each_entry(child, &ex_root->children, siblings) { - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(child->dev_type)) { struct sas_expander_device *ex = rphy_to_expander_device(child->rphy); @@ -1983,7 +1953,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) struct domain_device *child; int res; - pr_debug("ex %016llx phy%d new device attached\n", + pr_debug("ex %016llx phy%02d new device attached\n", SAS_ADDR(dev->sas_addr), phy_id); res = sas_ex_phy_discover(dev, phy_id); if (res) @@ -1998,8 +1968,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) list_for_each_entry(child, &dev->ex_dev.children, siblings) { if (SAS_ADDR(child->sas_addr) == SAS_ADDR(ex_phy->attached_sas_addr)) { - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(child->dev_type)) res = sas_discover_bfs_by_root(child); break; } @@ -2022,15 +1991,23 @@ static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old) return false; } -static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) +static int sas_rediscover_dev(struct domain_device *dev, int phy_id, + bool last, int sibling) { struct expander_device *ex = &dev->ex_dev; struct ex_phy *phy = &ex->ex_phy[phy_id]; enum sas_device_type type = SAS_PHY_UNUSED; - u8 sas_addr[8]; + u8 sas_addr[SAS_ADDR_SIZE]; + char msg[80] = ""; int res; - memset(sas_addr, 0, 8); + if (!last) + sprintf(msg, ", part of a wide port with phy%02d", sibling); + + pr_debug("ex %016llx rediscovering phy%02d%s\n", + SAS_ADDR(dev->sas_addr), phy_id, msg); + + memset(sas_addr, 0, SAS_ADDR_SIZE); res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type); switch (res) { case SMP_RESP_NO_PHY: @@ -2052,6 +2029,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) { phy->phy_state = PHY_EMPTY; sas_unregister_devs_sas_addr(dev, phy_id, last); + /* + * Even though the PHY is empty, for convenience we discover + * the PHY to update the PHY info, like negotiated linkrate. + */ + sas_ex_phy_discover(dev, phy_id); return res; } else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) && dev_type_flutter(type, phy->attached_dev_type)) { @@ -2062,13 +2044,13 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING) action = ", needs recovery"; - pr_debug("ex %016llx phy 0x%x broadcast flutter%s\n", + pr_debug("ex %016llx phy%02d broadcast flutter%s\n", SAS_ADDR(dev->sas_addr), phy_id, action); return res; } /* we always have to delete the old device when we went here */ - pr_info("ex %016llx phy 0x%x replace %016llx\n", + pr_info("ex %016llx phy%02d replace %016llx\n", SAS_ADDR(dev->sas_addr), phy_id, SAS_ADDR(phy->attached_sas_addr)); sas_unregister_devs_sas_addr(dev, phy_id, last); @@ -2098,7 +2080,7 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id) int i; bool last = true; /* is this the last phy of the port */ - pr_debug("ex %016llx phy%d originated BROADCAST(CHANGE)\n", + pr_debug("ex %016llx phy%02d originated BROADCAST(CHANGE)\n", SAS_ADDR(dev->sas_addr), phy_id); if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) { @@ -2109,13 +2091,11 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id) continue; if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(changed_phy->attached_sas_addr)) { - pr_debug("phy%d part of wide port with phy%d\n", - phy_id, i); last = false; break; } } - res = sas_rediscover_dev(dev, phy_id, last); + res = sas_rediscover_dev(dev, phy_id, last, i); } else res = sas_discover_new(dev, phy_id); return res; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index 9ead93df3a6e..eca2a6bf3601 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Serial Attached SCSI (SAS) Expander discovery and configuration * * Copyright (C) 2007 James E.J. Bottomley * <James.Bottomley@HansenPartnership.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; version 2 only. */ #include <linux/scatterlist.h> #include <linux/blkdev.h> diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 221340ee8651..21c43b18d5d5 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -1,26 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Serial Attached SCSI (SAS) Transport Layer initialization * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * */ #include <linux/module.h> @@ -87,25 +70,27 @@ EXPORT_SYMBOL_GPL(sas_free_task); /*------------ SAS addr hash -----------*/ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) { - const u32 poly = 0x00DB2777; - u32 r = 0; - int i; - - for (i = 0; i < 8; i++) { - int b; - for (b = 7; b >= 0; b--) { - r <<= 1; - if ((1 << b) & sas_addr[i]) { - if (!(r & 0x01000000)) - r ^= poly; - } else if (r & 0x01000000) - r ^= poly; - } - } - - hashed[0] = (r >> 16) & 0xFF; - hashed[1] = (r >> 8) & 0xFF ; - hashed[2] = r & 0xFF; + const u32 poly = 0x00DB2777; + u32 r = 0; + int i; + + for (i = 0; i < SAS_ADDR_SIZE; i++) { + int b; + + for (b = (SAS_ADDR_SIZE - 1); b >= 0; b--) { + r <<= 1; + if ((1 << b) & sas_addr[i]) { + if (!(r & 0x01000000)) + r ^= poly; + } else if (r & 0x01000000) { + r ^= poly; + } + } + } + + hashed[0] = (r >> 16) & 0xFF; + hashed[1] = (r >> 8) & 0xFF; + hashed[2] = r & 0xFF; } int sas_register_ha(struct sas_ha_struct *sas_ha) @@ -623,7 +608,7 @@ struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy) if (atomic_read(&phy->event_nr) > phy->ha->event_thres) { if (i->dft->lldd_control_phy) { if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) { - pr_notice("The phy%02d bursting events, shut it down.\n", + pr_notice("The phy%d bursting events, shut it down.\n", phy->id); sas_notify_phy_event(phy, PHYE_SHUTDOWN); } diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 2cdb981cf476..01f1738ce6df 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -1,26 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Serial Attached SCSI (SAS) class internal header file * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * */ #ifndef _SAS_INTERNAL_H_ diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 0374243c85d0..4ca4b1f30bd0 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Phy class * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include "sas_internal.h" @@ -35,7 +19,6 @@ static void sas_phye_loss_of_signal(struct work_struct *work) struct asd_sas_event *ev = to_asd_sas_event(work); struct asd_sas_phy *phy = ev->phy; - phy->in_shutdown = 0; phy->error = 0; sas_deform_port(phy, 1); } @@ -45,7 +28,6 @@ static void sas_phye_oob_done(struct work_struct *work) struct asd_sas_event *ev = to_asd_sas_event(work); struct asd_sas_phy *phy = ev->phy; - phy->in_shutdown = 0; phy->error = 0; } @@ -122,11 +104,11 @@ static void sas_phye_shutdown(struct work_struct *work) phy->enabled = 0; ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); if (ret) - pr_notice("lldd disable phy%02d returned %d\n", - phy->id, ret); + pr_notice("lldd disable phy%d returned %d\n", phy->id, + ret); } else - pr_notice("phy%02d is not enabled, cannot shutdown\n", - phy->id); + pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id); + phy->in_shutdown = 0; } /* ---------- Phy class registration ---------- */ diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 03fe479359b6..7c86fd248129 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Port class * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include "sas_internal.h" @@ -70,7 +54,7 @@ static void sas_resume_port(struct asd_sas_phy *phy) continue; } - if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(dev->dev_type)) { dev->ex_dev.ex_change_count = -1; for (i = 0; i < dev->ex_dev.num_phys; i++) { struct ex_phy *phy = &dev->ex_dev.ex_phy[i]; @@ -95,6 +79,7 @@ static void sas_form_port(struct asd_sas_phy *phy) int i; struct sas_ha_struct *sas_ha = phy->ha; struct asd_sas_port *port = phy->port; + struct domain_device *port_dev; struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); unsigned long flags; @@ -153,8 +138,9 @@ static void sas_form_port(struct asd_sas_phy *phy) } /* add the phy to the port */ + port_dev = port->port_dev; list_add_tail(&phy->port_phy_el, &port->phy_list); - sas_phy_set_target(phy, port->port_dev); + sas_phy_set_target(phy, port_dev); phy->port = port; port->num_phys++; port->phy_mask |= (1U << phy->id); @@ -184,14 +170,21 @@ static void sas_form_port(struct asd_sas_phy *phy) port->phy_mask, SAS_ADDR(port->attached_sas_addr)); - if (port->port_dev) - port->port_dev->pathways = port->num_phys; + if (port_dev) + port_dev->pathways = port->num_phys; /* Tell the LLDD about this port formation. */ if (si->dft->lldd_port_formed) si->dft->lldd_port_formed(phy); sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); + /* Only insert a revalidate event after initial discovery */ + if (port_dev && dev_is_expander(port_dev->dev_type)) { + struct expander_device *ex_dev = &port_dev->ex_dev; + + ex_dev->ex_change_count = -1; + sas_discover_event(port, DISCE_REVALIDATE_DOMAIN); + } flush_workqueue(sas_ha->disco_q); } @@ -254,6 +247,15 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone) spin_unlock(&port->phy_list_lock); spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); + /* Only insert revalidate event if the port still has members */ + if (port->port && dev && dev_is_expander(dev->dev_type)) { + struct expander_device *ex_dev = &dev->ex_dev; + + ex_dev->ex_change_count = -1; + sas_discover_event(port, DISCE_REVALIDATE_DOMAIN); + } + flush_workqueue(sas_ha->disco_q); + return; } diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index b775445892af..4f339f939a51 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -1,26 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Serial Attached SCSI (SAS) class SCSI Host glue. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * */ #include <linux/kthread.h> diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c index c3b9befad4e6..1ded7d85027e 100644 --- a/drivers/scsi/libsas/sas_task.c +++ b/drivers/scsi/libsas/sas_task.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only #include "sas_internal.h" diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 41d849f283f6..2c3bb8a966e5 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -274,6 +274,7 @@ struct lpfc_stats { uint32_t elsXmitADISC; uint32_t elsXmitLOGO; uint32_t elsXmitSCR; + uint32_t elsXmitRSCN; uint32_t elsXmitRNID; uint32_t elsXmitFARP; uint32_t elsXmitFARPR; @@ -819,6 +820,7 @@ struct lpfc_hba { uint32_t cfg_use_msi; uint32_t cfg_auto_imax; uint32_t cfg_fcp_imax; + uint32_t cfg_force_rscn; uint32_t cfg_cq_poll_threshold; uint32_t cfg_cq_max_proc_limit; uint32_t cfg_fcp_cpu_map; @@ -942,6 +944,7 @@ struct lpfc_hba { int brd_no; /* FC board number */ char SerialNumber[32]; /* adapter Serial Number */ char OptionROMVersion[32]; /* adapter BIOS / Fcode version */ + char BIOSVersion[16]; /* Boot BIOS version */ char ModelDesc[256]; /* Model Description */ char ModelName[80]; /* Model Name */ char ProgramType[256]; /* Program Type */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index ce3e541434dc..ea62322ffe2b 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -71,6 +71,23 @@ #define LPFC_REG_WRITE_KEY_SIZE 4 #define LPFC_REG_WRITE_KEY "EMLX" +const char *const trunk_errmsg[] = { /* map errcode */ + "", /* There is no such error code at index 0*/ + "link negotiated speed does not match existing" + " trunk - link was \"low\" speed", + "link negotiated speed does not match" + " existing trunk - link was \"middle\" speed", + "link negotiated speed does not match existing" + " trunk - link was \"high\" speed", + "Attached to non-trunking port - F_Port", + "Attached to non-trunking port - N_Port", + "FLOGI response timeout", + "non-FLOGI frame received", + "Invalid FLOGI response", + "Trunking initialization protocol", + "Trunk peer device mismatch", +}; + /** * lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules * @incr: integer to convert. @@ -114,7 +131,7 @@ static ssize_t lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); + return scnprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); } /** @@ -134,9 +151,9 @@ lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; if (phba->hba_flag & HBA_FIP_SUPPORT) - return snprintf(buf, PAGE_SIZE, "1\n"); + return scnprintf(buf, PAGE_SIZE, "1\n"); else - return snprintf(buf, PAGE_SIZE, "0\n"); + return scnprintf(buf, PAGE_SIZE, "0\n"); } static ssize_t @@ -159,6 +176,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, int i; int len = 0; char tmp[LPFC_MAX_NVME_INFO_TMP_LEN] = {0}; + unsigned long iflags = 0; if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n"); @@ -337,7 +355,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, phba->sli4_hba.io_xri_max, lpfc_sli4_get_els_iocb_cnt(phba)); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; /* Port state is only one of two values for now. */ if (localport->port_id) @@ -353,15 +371,15 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, wwn_to_u64(vport->fc_nodename.u.wwn), localport->port_id, statep); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { nrport = NULL; - spin_lock(&vport->phba->hbalock); + spin_lock_irqsave(&vport->phba->hbalock, iflags); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) nrport = rport->remoteport; - spin_unlock(&vport->phba->hbalock); + spin_unlock_irqrestore(&vport->phba->hbalock, iflags); if (!nrport) continue; @@ -380,39 +398,39 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, /* Tab in to show lport ownership. */ if (strlcat(buf, "NVME RPORT ", PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; if (phba->brd_no >= 10) { if (strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; } scnprintf(tmp, sizeof(tmp), "WWPN x%llx ", nrport->port_name); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; scnprintf(tmp, sizeof(tmp), "WWNN x%llx ", nrport->node_name); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; scnprintf(tmp, sizeof(tmp), "DID x%06x ", nrport->port_id); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; /* An NVME rport can have multiple roles. */ if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) { if (strlcat(buf, "INITIATOR ", PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; } if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) { if (strlcat(buf, "TARGET ", PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; } if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) { if (strlcat(buf, "DISCSRVC ", PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; } if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR | FC_PORT_ROLE_NVME_TARGET | @@ -420,12 +438,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, scnprintf(tmp, sizeof(tmp), "UNKNOWN ROLE x%x", nrport->port_role); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; } scnprintf(tmp, sizeof(tmp), "%s\n", statep); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto buffer_done; + goto rcu_unlock_buf_done; } rcu_read_unlock(); @@ -487,7 +505,13 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, atomic_read(&lport->cmpl_fcp_err)); strlcat(buf, tmp, PAGE_SIZE); -buffer_done: + /* RCU is already unlocked. */ + goto buffer_done; + + rcu_unlock_buf_done: + rcu_read_unlock(); + + buffer_done: len = strnlen(buf, PAGE_SIZE); if (unlikely(len >= (PAGE_SIZE - 1))) { @@ -564,14 +588,15 @@ lpfc_bg_info_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - if (phba->cfg_enable_bg) + if (phba->cfg_enable_bg) { if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) - return snprintf(buf, PAGE_SIZE, "BlockGuard Enabled\n"); + return scnprintf(buf, PAGE_SIZE, + "BlockGuard Enabled\n"); else - return snprintf(buf, PAGE_SIZE, + return scnprintf(buf, PAGE_SIZE, "BlockGuard Not Supported\n"); - else - return snprintf(buf, PAGE_SIZE, + } else + return scnprintf(buf, PAGE_SIZE, "BlockGuard Disabled\n"); } @@ -583,7 +608,7 @@ lpfc_bg_guard_err_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%llu\n", + return scnprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)phba->bg_guard_err_cnt); } @@ -595,7 +620,7 @@ lpfc_bg_apptag_err_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%llu\n", + return scnprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)phba->bg_apptag_err_cnt); } @@ -607,7 +632,7 @@ lpfc_bg_reftag_err_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%llu\n", + return scnprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)phba->bg_reftag_err_cnt); } @@ -625,7 +650,7 @@ lpfc_info_show(struct device *dev, struct device_attribute *attr, { struct Scsi_Host *host = class_to_shost(dev); - return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host)); + return scnprintf(buf, PAGE_SIZE, "%s\n", lpfc_info(host)); } /** @@ -644,7 +669,7 @@ lpfc_serialnum_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); + return scnprintf(buf, PAGE_SIZE, "%s\n", phba->SerialNumber); } /** @@ -666,7 +691,7 @@ lpfc_temp_sensor_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->temp_sensor_support); } /** @@ -685,7 +710,7 @@ lpfc_modeldesc_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); + return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelDesc); } /** @@ -704,7 +729,7 @@ lpfc_modelname_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); + return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelName); } /** @@ -723,7 +748,7 @@ lpfc_programtype_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); + return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ProgramType); } /** @@ -741,7 +766,7 @@ lpfc_mlomgmt_show(struct device *dev, struct device_attribute *attr, char *buf) struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", + return scnprintf(buf, PAGE_SIZE, "%d\n", (phba->sli.sli_flag & LPFC_MENLO_MAINT)); } @@ -761,7 +786,7 @@ lpfc_vportnum_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port); + return scnprintf(buf, PAGE_SIZE, "%s\n", phba->Port); } /** @@ -789,10 +814,10 @@ lpfc_fwrev_show(struct device *dev, struct device_attribute *attr, sli_family = phba->sli4_hba.pc_sli4_params.sli_family; if (phba->sli_rev < LPFC_SLI_REV4) - len = snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", + len = scnprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev); else - len = snprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n", + len = scnprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n", fwrev, phba->sli_rev, if_type, sli_family); return len; @@ -816,7 +841,7 @@ lpfc_hdw_show(struct device *dev, struct device_attribute *attr, char *buf) lpfc_vpd_t *vp = &phba->vpd; lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); - return snprintf(buf, PAGE_SIZE, "%s\n", hdw); + return scnprintf(buf, PAGE_SIZE, "%s\n", hdw); } /** @@ -837,10 +862,11 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr, char fwrev[FW_REV_STR_SIZE]; if (phba->sli_rev < LPFC_SLI_REV4) - return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); + return scnprintf(buf, PAGE_SIZE, "%s\n", + phba->OptionROMVersion); lpfc_decode_firmware_rev(phba, fwrev, 1); - return snprintf(buf, PAGE_SIZE, "%s\n", fwrev); + return scnprintf(buf, PAGE_SIZE, "%s\n", fwrev); } /** @@ -871,20 +897,20 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: if (phba->hba_flag & LINK_DISABLED) - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Link Down - User disabled\n"); else - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: - len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - "); + len += scnprintf(buf + len, PAGE_SIZE-len, "Link Up - "); switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK: - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Configuring Link\n"); break; case LPFC_FDISC: @@ -894,38 +920,40 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, case LPFC_NS_QRY: case LPFC_BUILD_DISC_LIST: case LPFC_DISC_AUTH: - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Discovery\n"); break; case LPFC_VPORT_READY: - len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, + "Ready\n"); break; case LPFC_VPORT_FAILED: - len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, + "Failed\n"); break; case LPFC_VPORT_UNKNOWN: - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Unknown\n"); break; } if (phba->sli.sli_flag & LPFC_MENLO_MAINT) - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, " Menlo Maint Mode\n"); else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { if (vport->fc_flag & FC_PUBLIC_LOOP) - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, " Public Loop\n"); else - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, " Private Loop\n"); } else { if (vport->fc_flag & FC_FABRIC) - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, " Fabric\n"); else - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, " Point-2-Point\n"); } } @@ -937,28 +965,28 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, struct lpfc_trunk_link link = phba->trunk_link; if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba)) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 0: Link %s %s\n", (link.link0.state == LPFC_LINK_UP) ? "Up" : "Down. ", trunk_errmsg[link.link0.fault]); if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba)) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 1: Link %s %s\n", (link.link1.state == LPFC_LINK_UP) ? "Up" : "Down. ", trunk_errmsg[link.link1.fault]); if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba)) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 2: Link %s %s\n", (link.link2.state == LPFC_LINK_UP) ? "Up" : "Down. ", trunk_errmsg[link.link2.fault]); if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba)) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 3: Link %s %s\n", (link.link3.state == LPFC_LINK_UP) ? "Up" : "Down. ", @@ -986,15 +1014,15 @@ lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; if (phba->sli_rev < LPFC_SLI_REV4) - return snprintf(buf, PAGE_SIZE, "fc\n"); + return scnprintf(buf, PAGE_SIZE, "fc\n"); if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) { if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_GE) - return snprintf(buf, PAGE_SIZE, "fcoe\n"); + return scnprintf(buf, PAGE_SIZE, "fcoe\n"); if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) - return snprintf(buf, PAGE_SIZE, "fc\n"); + return scnprintf(buf, PAGE_SIZE, "fc\n"); } - return snprintf(buf, PAGE_SIZE, "unknown\n"); + return scnprintf(buf, PAGE_SIZE, "unknown\n"); } /** @@ -1014,7 +1042,7 @@ lpfc_oas_supported_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->sli4_hba.pc_sli4_params.oas_supported); } @@ -1072,7 +1100,7 @@ lpfc_num_discovered_ports_show(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - return snprintf(buf, PAGE_SIZE, "%d\n", + return scnprintf(buf, PAGE_SIZE, "%d\n", vport->fc_map_cnt + vport->fc_unmap_cnt); } @@ -1204,6 +1232,20 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) psli = &phba->sli; + /* + * If freeing the queues have already started, don't access them. + * Otherwise set FREE_WAIT to indicate that queues are being used + * to hold the freeing process until we finish. + */ + spin_lock_irq(&phba->hbalock); + if (!(psli->sli_flag & LPFC_QUEUE_FREE_INIT)) { + psli->sli_flag |= LPFC_QUEUE_FREE_WAIT; + } else { + spin_unlock_irq(&phba->hbalock); + goto skip_wait; + } + spin_unlock_irq(&phba->hbalock); + /* Wait a little for things to settle down, but not * long enough for dev loss timeout to expire. */ @@ -1225,6 +1267,11 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) } } out: + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_QUEUE_FREE_WAIT; + spin_unlock_irq(&phba->hbalock); + +skip_wait: init_completion(&online_compl); rc = lpfc_workq_post_event(phba, &status, &online_compl, type); if (rc == 0) @@ -1258,7 +1305,7 @@ out: * -EBUSY, port is not in offline state * 0, successful */ -int +static int lpfc_reset_pci_bus(struct lpfc_hba *phba) { struct pci_dev *pdev = phba->pcidev; @@ -1586,10 +1633,10 @@ lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); } -int +static int lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out) { LPFC_MBOXQ_t *mbox = NULL; @@ -1675,7 +1722,7 @@ lpfc_board_mode_show(struct device *dev, struct device_attribute *attr, else state = "online"; - return snprintf(buf, PAGE_SIZE, "%s\n", state); + return scnprintf(buf, PAGE_SIZE, "%s\n", state); } /** @@ -1901,8 +1948,8 @@ lpfc_max_rpi_show(struct device *dev, struct device_attribute *attr, uint32_t cnt; if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", cnt); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); + return scnprintf(buf, PAGE_SIZE, "%d\n", cnt); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } /** @@ -1929,8 +1976,8 @@ lpfc_used_rpi_show(struct device *dev, struct device_attribute *attr, uint32_t cnt, acnt; if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); + return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } /** @@ -1957,8 +2004,8 @@ lpfc_max_xri_show(struct device *dev, struct device_attribute *attr, uint32_t cnt; if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", cnt); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); + return scnprintf(buf, PAGE_SIZE, "%d\n", cnt); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } /** @@ -1985,8 +2032,8 @@ lpfc_used_xri_show(struct device *dev, struct device_attribute *attr, uint32_t cnt, acnt; if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); + return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } /** @@ -2013,8 +2060,8 @@ lpfc_max_vpi_show(struct device *dev, struct device_attribute *attr, uint32_t cnt; if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", cnt); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); + return scnprintf(buf, PAGE_SIZE, "%d\n", cnt); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } /** @@ -2041,8 +2088,8 @@ lpfc_used_vpi_show(struct device *dev, struct device_attribute *attr, uint32_t cnt, acnt; if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt)) - return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); + return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } /** @@ -2067,10 +2114,10 @@ lpfc_npiv_info_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; if (!(phba->max_vpi)) - return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n"); + return scnprintf(buf, PAGE_SIZE, "NPIV Not Supported\n"); if (vport->port_type == LPFC_PHYSICAL_PORT) - return snprintf(buf, PAGE_SIZE, "NPIV Physical\n"); - return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi); + return scnprintf(buf, PAGE_SIZE, "NPIV Physical\n"); + return scnprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi); } /** @@ -2092,7 +2139,7 @@ lpfc_poll_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll); + return scnprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll); } /** @@ -2196,7 +2243,7 @@ lpfc_fips_level_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level); } /** @@ -2215,7 +2262,7 @@ lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev); } /** @@ -2234,7 +2281,7 @@ lpfc_dss_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%s - %sOperational\n", + return scnprintf(buf, PAGE_SIZE, "%s - %sOperational\n", (phba->cfg_enable_dss) ? "Enabled" : "Disabled", (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ? "" : "Not "); @@ -2263,7 +2310,7 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev, uint16_t max_nr_virtfn; max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba); - return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); + return scnprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); } static inline bool lpfc_rangecheck(uint val, uint min, uint max) @@ -2323,7 +2370,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ struct lpfc_hba *phba = vport->phba;\ - return snprintf(buf, PAGE_SIZE, "%d\n",\ + return scnprintf(buf, PAGE_SIZE, "%d\n",\ phba->cfg_##attr);\ } @@ -2351,7 +2398,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ struct lpfc_hba *phba = vport->phba;\ uint val = 0;\ val = phba->cfg_##attr;\ - return snprintf(buf, PAGE_SIZE, "%#x\n",\ + return scnprintf(buf, PAGE_SIZE, "%#x\n",\ phba->cfg_##attr);\ } @@ -2487,7 +2534,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ + return scnprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ } /** @@ -2512,7 +2559,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ + return scnprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ } /** @@ -2784,7 +2831,7 @@ lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", + return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)phba->cfg_soft_wwpn); } @@ -2881,7 +2928,7 @@ lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, { struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", + return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)phba->cfg_soft_wwnn); } @@ -2947,7 +2994,7 @@ lpfc_oas_tgt_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", + return scnprintf(buf, PAGE_SIZE, "0x%llx\n", wwn_to_u64(phba->cfg_oas_tgt_wwpn)); } @@ -3015,7 +3062,7 @@ lpfc_oas_priority_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_priority); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_priority); } /** @@ -3078,7 +3125,7 @@ lpfc_oas_vpt_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", + return scnprintf(buf, PAGE_SIZE, "0x%llx\n", wwn_to_u64(phba->cfg_oas_vpt_wwpn)); } @@ -3149,7 +3196,7 @@ lpfc_oas_lun_state_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state); } /** @@ -3213,7 +3260,7 @@ lpfc_oas_lun_status_show(struct device *dev, struct device_attribute *attr, if (!(phba->cfg_oas_flags & OAS_LUN_VALID)) return -EFAULT; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status); } static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO, lpfc_oas_lun_status_show, NULL); @@ -3365,7 +3412,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, if (oas_lun != NOT_OAS_ENABLED_LUN) phba->cfg_oas_flags |= OAS_LUN_VALID; - len += snprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun); + len += scnprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun); return len; } @@ -3499,7 +3546,7 @@ lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf) struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max); + return scnprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max); } static DEVICE_ATTR(iocb_hw, S_IRUGO, @@ -3511,7 +3558,7 @@ lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf) struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba); - return snprintf(buf, PAGE_SIZE, "%d\n", + return scnprintf(buf, PAGE_SIZE, "%d\n", pring ? pring->txq_max : 0); } @@ -3525,7 +3572,7 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba); - return snprintf(buf, PAGE_SIZE, "%d\n", + return scnprintf(buf, PAGE_SIZE, "%d\n", pring ? pring->txcmplq_max : 0); } @@ -3561,7 +3608,7 @@ lpfc_nodev_tmo_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo); + return scnprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo); } /** @@ -4912,6 +4959,64 @@ static DEVICE_ATTR(lpfc_req_fw_upgrade, S_IRUGO | S_IWUSR, lpfc_request_firmware_upgrade_store); /** + * lpfc_force_rscn_store + * + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: unused string + * @count: unused variable. + * + * Description: + * Force the switch to send a RSCN to all other NPorts in our zone + * If we are direct connect pt2pt, build the RSCN command ourself + * and send to the other NPort. Not supported for private loop. + * + * Returns: + * 0 - on success + * -EIO - if command is not sent + **/ +static ssize_t +lpfc_force_rscn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + int i; + + i = lpfc_issue_els_rscn(vport, 0); + if (i) + return -EIO; + return strlen(buf); +} + +/* + * lpfc_force_rscn: Force an RSCN to be sent to all remote NPorts + * connected to the HBA. + * + * Value range is any ascii value + */ +static int lpfc_force_rscn; +module_param(lpfc_force_rscn, int, 0644); +MODULE_PARM_DESC(lpfc_force_rscn, + "Force an RSCN to be sent to all remote NPorts"); +lpfc_param_show(force_rscn) + +/** + * lpfc_force_rscn_init - Force an RSCN to be sent to all remote NPorts + * @phba: lpfc_hba pointer. + * @val: unused value. + * + * Returns: + * zero if val saved. + **/ +static int +lpfc_force_rscn_init(struct lpfc_hba *phba, int val) +{ + return 0; +} +static DEVICE_ATTR_RW(lpfc_force_rscn); + +/** * lpfc_fcp_imax_store * * @dev: class device that is converted into a Scsi_host. @@ -5075,7 +5180,8 @@ lpfc_cq_max_proc_limit_store(struct device *dev, struct device_attribute *attr, /* set the values on the cq's */ for (i = 0; i < phba->cfg_irq_chann; i++) { - eq = phba->sli4_hba.hdwq[i].hba_eq; + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[i].eq; if (!eq) continue; @@ -5169,12 +5275,12 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, switch (phba->cfg_fcp_cpu_map) { case 0: - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "fcp_cpu_map: No mapping (%d)\n", phba->cfg_fcp_cpu_map); return len; case 1: - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "fcp_cpu_map: HBA centric mapping (%d): " "%d of %d CPUs online from %d possible CPUs\n", phba->cfg_fcp_cpu_map, num_online_cpus(), @@ -5188,43 +5294,52 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, cpup = &phba->sli4_hba.cpu_map[phba->sli4_hba.curr_disp_cpu]; if (!cpu_present(phba->sli4_hba.curr_disp_cpu)) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "CPU %02d not present\n", phba->sli4_hba.curr_disp_cpu); else if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) { if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY) - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d hdwq None " - "physid %d coreid %d ht %d\n", + "physid %d coreid %d ht %d ua %d\n", phba->sli4_hba.curr_disp_cpu, - cpup->phys_id, - cpup->core_id, cpup->hyper); + cpup->phys_id, cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN)); else - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d EQ %04d hdwq %04d " - "physid %d coreid %d ht %d\n", + "physid %d coreid %d ht %d ua %d\n", phba->sli4_hba.curr_disp_cpu, cpup->eq, cpup->hdwq, cpup->phys_id, - cpup->core_id, cpup->hyper); + cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN)); } else { if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY) - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d hdwq None " - "physid %d coreid %d ht %d IRQ %d\n", + "physid %d coreid %d ht %d ua %d IRQ %d\n", phba->sli4_hba.curr_disp_cpu, cpup->phys_id, - cpup->core_id, cpup->hyper, cpup->irq); + cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN), + cpup->irq); else - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d EQ %04d hdwq %04d " - "physid %d coreid %d ht %d IRQ %d\n", + "physid %d coreid %d ht %d ua %d IRQ %d\n", phba->sli4_hba.curr_disp_cpu, cpup->eq, cpup->hdwq, cpup->phys_id, - cpup->core_id, cpup->hyper, cpup->irq); + cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN), + cpup->irq); } phba->sli4_hba.curr_disp_cpu++; @@ -5233,7 +5348,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, if (phba->sli4_hba.curr_disp_cpu < phba->sli4_hba.num_possible_cpu && (len >= (PAGE_SIZE - 64))) { - len += snprintf(buf + len, + len += scnprintf(buf + len, PAGE_SIZE - len, "more...\n"); break; } @@ -5753,10 +5868,10 @@ lpfc_sg_seg_cnt_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; int len; - len = snprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n", + len = scnprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n", phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt); - len += snprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n", + len += scnprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n", phba->cfg_sg_seg_cnt, phba->cfg_scsi_seg_cnt, phba->cfg_nvme_seg_cnt); return len; @@ -5911,6 +6026,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_nvme_oas, &dev_attr_lpfc_nvme_embed_cmd, &dev_attr_lpfc_fcp_imax, + &dev_attr_lpfc_force_rscn, &dev_attr_lpfc_cq_poll_threshold, &dev_attr_lpfc_cq_max_proc_limit, &dev_attr_lpfc_fcp_cpu_map, @@ -6755,7 +6871,7 @@ lpfc_show_rport_##field (struct device *dev, \ { \ struct fc_rport *rport = transport_class_to_rport(dev); \ struct lpfc_rport_data *rdata = rport->hostdata; \ - return snprintf(buf, sz, format_string, \ + return scnprintf(buf, sz, format_string, \ (rdata->target) ? cast rdata->target->field : 0); \ } @@ -6958,6 +7074,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_nvme_oas_init(phba, lpfc_nvme_oas); lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd); lpfc_fcp_imax_init(phba, lpfc_fcp_imax); + lpfc_force_rscn_init(phba, lpfc_force_rscn); lpfc_cq_poll_threshold_init(phba, lpfc_cq_poll_threshold); lpfc_cq_max_proc_limit_init(phba, lpfc_cq_max_proc_limit); lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map); @@ -7003,6 +7120,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) if (phba->sli_rev != LPFC_SLI_REV4) { /* NVME only supported on SLI4 */ phba->nvmet_support = 0; + phba->cfg_nvmet_mrq = 0; phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; phba->cfg_enable_bbcr = 0; phba->cfg_xri_rebalancing = 0; @@ -7104,7 +7222,7 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) } else { /* Not NVME Target mode. Turn off Target parameters. */ phba->nvmet_support = 0; - phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_OFF; + phba->cfg_nvmet_mrq = 0; phba->cfg_nvmet_fb_size = 0; } } diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index f2494d3b365c..b7216d694bff 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-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1968,14 +1968,17 @@ link_diag_state_set_out: } /** - * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic + * lpfc_sli4_bsg_set_loopback_mode - set sli4 internal loopback diagnostic * @phba: Pointer to HBA context object. + * @mode: loopback mode to set + * @link_no: link number for loopback mode to set * * This function is responsible for issuing a sli4 mailbox command for setting - * up internal loopback diagnostic. + * up loopback diagnostic for a link. */ static int -lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) +lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode, + uint32_t link_no) { LPFC_MBOXQ_t *pmboxq; uint32_t req_len, alloc_len; @@ -1996,11 +1999,19 @@ lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) } link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; bf_set(lpfc_mbx_set_diag_state_link_num, - &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no); - bf_set(lpfc_mbx_set_diag_state_link_type, - &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp); + &link_diag_loopback->u.req, link_no); + + if (phba->sli4_hba.conf_trunk & (1 << link_no)) { + bf_set(lpfc_mbx_set_diag_state_link_type, + &link_diag_loopback->u.req, LPFC_LNK_FC_TRUNKED); + } else { + bf_set(lpfc_mbx_set_diag_state_link_type, + &link_diag_loopback->u.req, + phba->sli4_hba.lnk_info.lnk_tp); + } + bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, - LPFC_DIAG_LOOPBACK_TYPE_INTERNAL); + mode); mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { @@ -2054,7 +2065,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) struct fc_bsg_request *bsg_request = job->request; struct fc_bsg_reply *bsg_reply = job->reply; struct diag_mode_set *loopback_mode; - uint32_t link_flags, timeout; + uint32_t link_flags, timeout, link_no; int i, rc = 0; /* no data to return just the return code */ @@ -2069,12 +2080,39 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) (int)(sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set))); rc = -EINVAL; - goto job_error; + goto job_done; + } + + loopback_mode = (struct diag_mode_set *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + link_flags = loopback_mode->type; + timeout = loopback_mode->timeout * 100; + + if (loopback_mode->physical_link == -1) + link_no = phba->sli4_hba.lnk_info.lnk_no; + else + link_no = loopback_mode->physical_link; + + if (link_flags == DISABLE_LOOP_BACK) { + rc = lpfc_sli4_bsg_set_loopback_mode(phba, + LPFC_DIAG_LOOPBACK_TYPE_DISABLE, + link_no); + if (!rc) { + /* Unset the need disable bit */ + phba->sli4_hba.conf_trunk &= ~((1 << link_no) << 4); + } + goto job_done; + } else { + /* Check if we need to disable the loopback state */ + if (phba->sli4_hba.conf_trunk & ((1 << link_no) << 4)) { + rc = -EPERM; + goto job_done; + } } rc = lpfc_bsg_diag_mode_enter(phba); if (rc) - goto job_error; + goto job_done; /* indicate we are in loobpack diagnostic mode */ spin_lock_irq(&phba->hbalock); @@ -2084,15 +2122,11 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) /* reset port to start frome scratch */ rc = lpfc_selective_reset(phba); if (rc) - goto job_error; + goto job_done; /* bring the link to diagnostic mode */ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3129 Bring link to diagnostic state.\n"); - loopback_mode = (struct diag_mode_set *) - bsg_request->rqst_data.h_vendor.vendor_cmd; - link_flags = loopback_mode->type; - timeout = loopback_mode->timeout * 100; rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); if (rc) { @@ -2120,13 +2154,54 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3132 Set up loopback mode:x%x\n", link_flags); - if (link_flags == INTERNAL_LOOP_BACK) - rc = lpfc_sli4_bsg_set_internal_loopback(phba); - else if (link_flags == EXTERNAL_LOOP_BACK) - rc = lpfc_hba_init_link_fc_topology(phba, - FLAGS_TOPOLOGY_MODE_PT_PT, - MBX_NOWAIT); - else { + switch (link_flags) { + case INTERNAL_LOOP_BACK: + if (phba->sli4_hba.conf_trunk & (1 << link_no)) { + rc = lpfc_sli4_bsg_set_loopback_mode(phba, + LPFC_DIAG_LOOPBACK_TYPE_INTERNAL, + link_no); + } else { + /* Trunk is configured, but link is not in this trunk */ + if (phba->sli4_hba.conf_trunk) { + rc = -ELNRNG; + goto loopback_mode_exit; + } + + rc = lpfc_sli4_bsg_set_loopback_mode(phba, + LPFC_DIAG_LOOPBACK_TYPE_INTERNAL, + link_no); + } + + if (!rc) { + /* Set the need disable bit */ + phba->sli4_hba.conf_trunk |= (1 << link_no) << 4; + } + + break; + case EXTERNAL_LOOP_BACK: + if (phba->sli4_hba.conf_trunk & (1 << link_no)) { + rc = lpfc_sli4_bsg_set_loopback_mode(phba, + LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED, + link_no); + } else { + /* Trunk is configured, but link is not in this trunk */ + if (phba->sli4_hba.conf_trunk) { + rc = -ELNRNG; + goto loopback_mode_exit; + } + + rc = lpfc_sli4_bsg_set_loopback_mode(phba, + LPFC_DIAG_LOOPBACK_TYPE_SERDES, + link_no); + } + + if (!rc) { + /* Set the need disable bit */ + phba->sli4_hba.conf_trunk |= (1 << link_no) << 4; + } + + break; + default: rc = -EINVAL; lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, "3141 Loopback mode:x%x not supported\n", @@ -2185,7 +2260,7 @@ loopback_mode_exit: } lpfc_bsg_diag_mode_exit(phba); -job_error: +job_done: /* make error code available to userspace */ bsg_reply->result = rc; /* complete the job back to userspace if no error */ @@ -5666,7 +5741,7 @@ lpfc_get_trunk_info(struct bsg_job *job) event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000; event_reply->logical_speed = - phba->sli4_hba.link_state.logical_speed / 100; + phba->sli4_hba.link_state.logical_speed / 1000; job_error: bsg_reply->result = rc; bsg_job_done(job, bsg_reply->result, diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 9151824beea4..d1708133fd54 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2010-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -68,6 +68,7 @@ struct send_mgmt_resp { }; +#define DISABLE_LOOP_BACK 0x0 /* disables loop back */ #define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */ #define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */ @@ -75,6 +76,7 @@ struct diag_mode_set { uint32_t command; uint32_t type; uint32_t timeout; + uint32_t physical_link; }; struct sli4_link_diag { diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index e0b14d791b8c..68e9f96242d3 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -141,6 +141,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); +int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry); int lpfc_issue_fabric_reglogin(struct lpfc_vport *); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); @@ -355,6 +356,7 @@ void lpfc_mbox_timeout_handler(struct lpfc_hba *); struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, struct lpfc_name *); +struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *vport); int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -555,6 +557,8 @@ void lpfc_ras_stop_fwlog(struct lpfc_hba *phba); int lpfc_check_fwlog_support(struct lpfc_hba *phba); /* NVME interfaces. */ +void lpfc_nvme_rescan_port(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); void lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp); int lpfc_nvme_register_port(struct lpfc_vport *vport, @@ -568,7 +572,8 @@ void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba); void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb); void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, - struct rqb_dmabuf *nvmebuf, uint64_t isr_ts); + struct rqb_dmabuf *nvmebuf, uint64_t isr_ts, + uint8_t cqflag); void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba); void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 7290573110fe..ec72c39997d2 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -886,7 +886,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } if (lpfc_error_lost_link(irsp)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "4101 NS query failed due to link event\n"); + "4166 NS query failed due to link event\n"); if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); goto out; @@ -907,7 +907,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * Re-issue the NS cmd */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "4102 Process Deferred RSCN Data: x%x x%x\n", + "4167 Process Deferred RSCN Data: x%x x%x\n", vport->fc_flag, vport->fc_rscn_id_cnt); lpfc_els_handle_rscn(vport); @@ -1430,7 +1430,7 @@ lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, * Name object. NPIV is not in play so this integer * value is sufficient and unique per FC-ID. */ - n = snprintf(symbol, size, "%d", vport->phba->brd_no); + n = scnprintf(symbol, size, "%d", vport->phba->brd_no); return n; } @@ -1444,26 +1444,26 @@ lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol, lpfc_decode_firmware_rev(vport->phba, fwrev, 0); - n = snprintf(symbol, size, "Emulex %s", vport->phba->ModelName); + n = scnprintf(symbol, size, "Emulex %s", vport->phba->ModelName); if (size < n) return n; - n += snprintf(symbol + n, size - n, " FV%s", fwrev); + n += scnprintf(symbol + n, size - n, " FV%s", fwrev); if (size < n) return n; - n += snprintf(symbol + n, size - n, " DV%s.", + n += scnprintf(symbol + n, size - n, " DV%s.", lpfc_release_version); if (size < n) return n; - n += snprintf(symbol + n, size - n, " HN:%s.", + n += scnprintf(symbol + n, size - n, " HN:%s.", init_utsname()->nodename); if (size < n) return n; /* Note :- OS name is "Linux" */ - n += snprintf(symbol + n, size - n, " OS:%s\n", + n += scnprintf(symbol + n, size - n, " OS:%s", init_utsname()->sysname); return n; } @@ -2005,8 +2005,11 @@ lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport, ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; memset(ae, 0, 256); + /* This string MUST be consistent with other FC platforms + * supported by Broadcom. + */ strncpy(ae->un.AttrString, - "Broadcom Inc.", + "Emulex Corporation", sizeof(ae->un.AttrString)); len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); @@ -2301,7 +2304,8 @@ lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport, ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; memset(ae, 0, 256); - lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1); + strlcat(ae->un.AttrString, phba->BIOSVersion, + sizeof(ae->un.AttrString)); len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); len += (len & 3) ? (4 - (len & 3)) : 4; @@ -2354,16 +2358,22 @@ static int lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { + struct lpfc_hba *phba = vport->phba; struct lpfc_fdmi_attr_entry *ae; uint32_t size; ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; memset(ae, 0, 32); - ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */ - ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */ - ae->un.AttrTypes[6] = 0x01; /* Type 40 - NVME */ - ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */ + ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ + ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ + ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + + /* Check to see if Firmware supports NVME and on physical port */ + if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) && + phba->sli4_hba.pc_sli4_params.nvme) + ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */ + size = FOURBYTES + 32; ad->AttrLen = cpu_to_be16(size); ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES); @@ -2673,9 +2683,14 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; memset(ae, 0, 32); - ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */ - ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */ - ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */ + ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ + ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ + ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + + /* Check to see if NVME is configured or not */ + if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */ + size = FOURBYTES + 32; ad->AttrLen = cpu_to_be16(size); ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES); @@ -3092,6 +3107,7 @@ port_out: case SLI_MGMT_GHAT: case SLI_MGMT_GRPL: rsp_size = FC_MAX_NS_RSP; + /* fall through */ case SLI_MGMT_DHBA: case SLI_MGMT_DHAT: pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID; @@ -3104,6 +3120,7 @@ port_out: case SLI_MGMT_GPAT: case SLI_MGMT_GPAS: rsp_size = FC_MAX_NS_RSP; + /* fall through */ case SLI_MGMT_DPRT: case SLI_MGMT_DPA: pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 1215eaa530db..1ee857d9d165 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -170,7 +170,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, + len += scnprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } for (i = 0; i < index; i++) { @@ -181,7 +181,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, + len += scnprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } @@ -236,7 +236,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, + len += scnprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } for (i = 0; i < index; i++) { @@ -247,7 +247,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, + len += scnprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } @@ -307,7 +307,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) i = lpfc_debugfs_last_hbq; - len += snprintf(buf+len, size-len, "HBQ %d Info\n", i); + len += scnprintf(buf+len, size-len, "HBQ %d Info\n", i); hbqs = &phba->hbqs[i]; posted = 0; @@ -315,21 +315,21 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) posted++; hip = lpfc_hbq_defs[i]; - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n", hip->hbq_index, hip->profile, hip->rn, hip->buffer_count, hip->init_count, hip->add_count, posted); raw_index = phba->hbq_get[i]; getidx = le32_to_cpu(raw_index); - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; for (j=0; j<hbqs->entry_count; j++) { - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "%03d: %08x %04x %05x ", j, le32_to_cpu(hbqe->bde.addrLow), le32_to_cpu(hbqe->bde.tus.w), @@ -341,14 +341,16 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) low = hbqs->hbqPutIdx - posted; if (low >= 0) { if ((j >= hbqs->hbqPutIdx) || (j < low)) { - len += snprintf(buf+len, size-len, "Unused\n"); + len += scnprintf(buf + len, size - len, + "Unused\n"); goto skipit; } } else { if ((j >= hbqs->hbqPutIdx) && (j < (hbqs->entry_count+low))) { - len += snprintf(buf+len, size-len, "Unused\n"); + len += scnprintf(buf + len, size - len, + "Unused\n"); goto skipit; } } @@ -358,7 +360,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); if (phys == le32_to_cpu(hbqe->bde.addrLow)) { - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "Buf%d: %p %06x\n", i, hbq_buf->dbuf.virt, hbq_buf->tag); found = 1; @@ -367,7 +369,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) i++; } if (!found) { - len += snprintf(buf+len, size-len, "No DMAinfo?\n"); + len += scnprintf(buf+len, size-len, "No DMAinfo?\n"); } skipit: hbqe++; @@ -413,14 +415,14 @@ lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size) break; qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool]; - len += snprintf(buf + len, size - len, "HdwQ %d Info ", i); + len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i); spin_lock_irqsave(&qp->abts_scsi_buf_list_lock, iflag); spin_lock(&qp->abts_nvme_buf_list_lock); spin_lock(&qp->io_buf_list_get_lock); spin_lock(&qp->io_buf_list_put_lock); out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs + qp->abts_scsi_io_bufs + qp->abts_nvme_io_bufs); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "tot:%d get:%d put:%d mt:%d " "ABTS scsi:%d nvme:%d Out:%d\n", qp->total_io_bufs, qp->get_io_bufs, qp->put_io_bufs, @@ -612,9 +614,9 @@ lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size) break; qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_lock]; - len += snprintf(buf + len, size - len, "HdwQ %03d Lock ", i); + len += scnprintf(buf + len, size - len, "HdwQ %03d Lock ", i); if (phba->cfg_xri_rebalancing) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "get_pvt:%d mv_pvt:%d " "mv2pub:%d mv2pvt:%d " "put_pvt:%d put_pub:%d wq:%d\n", @@ -626,7 +628,7 @@ lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size) qp->lock_conflict.free_pub_pool, qp->lock_conflict.wq_access); } else { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "get:%d put:%d free:%d wq:%d\n", qp->lock_conflict.alloc_xri_get, qp->lock_conflict.alloc_xri_put, @@ -678,7 +680,7 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) off = 0; spin_lock_irq(&phba->hbalock); - len += snprintf(buf+len, size-len, "HBA SLIM\n"); + len += scnprintf(buf+len, size-len, "HBA SLIM\n"); lpfc_memcpy_from_slim(buffer, phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024); @@ -692,7 +694,7 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) i = 1024; while (i > 0) { - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); @@ -736,11 +738,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) off = 0; spin_lock_irq(&phba->hbalock); - len += snprintf(buf+len, size-len, "SLIM Mailbox\n"); + len += scnprintf(buf+len, size-len, "SLIM Mailbox\n"); ptr = (uint32_t *)phba->slim2p.virt; i = sizeof(MAILBOX_t); while (i > 0) { - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); @@ -749,11 +751,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) off += (8 * sizeof(uint32_t)); } - len += snprintf(buf+len, size-len, "SLIM PCB\n"); + len += scnprintf(buf+len, size-len, "SLIM PCB\n"); ptr = (uint32_t *)phba->pcb; i = sizeof(PCB_t); while (i > 0) { - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); @@ -766,7 +768,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) for (i = 0; i < 4; i++) { pgpp = &phba->port_gp[i]; pring = &psli->sli3_ring[i]; - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "Ring %d: CMD GetInx:%d " "(Max:%d Next:%d " "Local:%d flg:x%x) " @@ -783,7 +785,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) word1 = readl(phba->CAregaddr); word2 = readl(phba->HSregaddr); word3 = readl(phba->HCregaddr); - len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x " + len += scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x " "HC:%08x\n", word0, word1, word2, word3); } spin_unlock_irq(&phba->hbalock); @@ -821,12 +823,12 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE); outio = 0; - len += snprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n"); + len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n"); spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { iocnt = 0; if (!cnt) { - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "Missing Nodelist Entries\n"); break; } @@ -864,63 +866,63 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) default: statep = "UNKNOWN"; } - len += snprintf(buf+len, size-len, "%s DID:x%06x ", + len += scnprintf(buf+len, size-len, "%s DID:x%06x ", statep, ndlp->nlp_DID); - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "WWPN x%llx ", wwn_to_u64(ndlp->nlp_portname.u.wwn)); - len += snprintf(buf+len, size-len, + len += scnprintf(buf+len, size-len, "WWNN x%llx ", wwn_to_u64(ndlp->nlp_nodename.u.wwn)); if (ndlp->nlp_flag & NLP_RPI_REGISTERED) - len += snprintf(buf+len, size-len, "RPI:%03d ", + len += scnprintf(buf+len, size-len, "RPI:%03d ", ndlp->nlp_rpi); else - len += snprintf(buf+len, size-len, "RPI:none "); - len += snprintf(buf+len, size-len, "flag:x%08x ", + len += scnprintf(buf+len, size-len, "RPI:none "); + len += scnprintf(buf+len, size-len, "flag:x%08x ", ndlp->nlp_flag); if (!ndlp->nlp_type) - len += snprintf(buf+len, size-len, "UNKNOWN_TYPE "); + len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) - len += snprintf(buf+len, size-len, "FC_NODE "); + len += scnprintf(buf+len, size-len, "FC_NODE "); if (ndlp->nlp_type & NLP_FABRIC) { - len += snprintf(buf+len, size-len, "FABRIC "); + len += scnprintf(buf+len, size-len, "FABRIC "); iocnt = 0; } if (ndlp->nlp_type & NLP_FCP_TARGET) - len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ", + len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ", ndlp->nlp_sid); if (ndlp->nlp_type & NLP_FCP_INITIATOR) - len += snprintf(buf+len, size-len, "FCP_INITIATOR "); + len += scnprintf(buf+len, size-len, "FCP_INITIATOR "); if (ndlp->nlp_type & NLP_NVME_TARGET) - len += snprintf(buf + len, + len += scnprintf(buf + len, size - len, "NVME_TGT sid:%d ", NLP_NO_SID); if (ndlp->nlp_type & NLP_NVME_INITIATOR) - len += snprintf(buf + len, + len += scnprintf(buf + len, size - len, "NVME_INITIATOR "); - len += snprintf(buf+len, size-len, "usgmap:%x ", + len += scnprintf(buf+len, size-len, "usgmap:%x ", ndlp->nlp_usg_map); - len += snprintf(buf+len, size-len, "refcnt:%x", + len += scnprintf(buf+len, size-len, "refcnt:%x", kref_read(&ndlp->kref)); if (iocnt) { i = atomic_read(&ndlp->cmd_pending); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, " OutIO:x%x Qdepth x%x", i, ndlp->cmd_qdepth); outio += i; } - len += snprintf(buf + len, size - len, "defer:%x ", + len += scnprintf(buf + len, size - len, "defer:%x ", ndlp->nlp_defer_did); - len += snprintf(buf+len, size-len, "\n"); + len += scnprintf(buf+len, size-len, "\n"); } spin_unlock_irq(shost->host_lock); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "\nOutstanding IO x%x\n", outio); if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "\nNVME Targetport Entry ...\n"); /* Port state is only one of two values for now. */ @@ -928,18 +930,18 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) statep = "REGISTERED"; else statep = "INIT"; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "TGT WWNN x%llx WWPN x%llx State %s\n", wwn_to_u64(vport->fc_nodename.u.wwn), wwn_to_u64(vport->fc_portname.u.wwn), statep); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, " Targetport DID x%06x\n", phba->targetport->port_id); goto out_exit; } - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "\nNVME Lport/Rport Entries ...\n"); localport = vport->localport; @@ -954,11 +956,11 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) else statep = "UNKNOWN "; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Lport DID x%06x PortState %s\n", localport->port_id, statep); - len += snprintf(buf + len, size - len, "\tRport List:\n"); + len += scnprintf(buf + len, size - len, "\tRport List:\n"); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { /* local short-hand pointer. */ spin_lock(&phba->hbalock); @@ -985,32 +987,32 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) } /* Tab in to show lport ownership. */ - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "\t%s Port ID:x%06x ", statep, nrport->port_id); - len += snprintf(buf + len, size - len, "WWPN x%llx ", + len += scnprintf(buf + len, size - len, "WWPN x%llx ", nrport->port_name); - len += snprintf(buf + len, size - len, "WWNN x%llx ", + len += scnprintf(buf + len, size - len, "WWNN x%llx ", nrport->node_name); /* An NVME rport can have multiple roles. */ if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "INITIATOR "); if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "TARGET "); if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "DISCSRVC "); if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR | FC_PORT_ROLE_NVME_TARGET | FC_PORT_ROLE_NVME_DISCOVERY)) - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "UNKNOWN ROLE x%x", nrport->port_role); /* Terminate the string. */ - len += snprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "\n"); } spin_unlock_irq(shost->host_lock); @@ -1049,35 +1051,35 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) if (!phba->targetport) return len; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "\nNVME Targetport Statistics\n"); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "LS: Rcv %08x Drop %08x Abort %08x\n", atomic_read(&tgtp->rcv_ls_req_in), atomic_read(&tgtp->rcv_ls_req_drop), atomic_read(&tgtp->xmt_ls_abort)); if (atomic_read(&tgtp->rcv_ls_req_in) != atomic_read(&tgtp->rcv_ls_req_out)) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Rcv LS: in %08x != out %08x\n", atomic_read(&tgtp->rcv_ls_req_in), atomic_read(&tgtp->rcv_ls_req_out)); } - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "LS: Xmt %08x Drop %08x Cmpl %08x\n", atomic_read(&tgtp->xmt_ls_rsp), atomic_read(&tgtp->xmt_ls_drop), atomic_read(&tgtp->xmt_ls_rsp_cmpl)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "LS: RSP Abort %08x xb %08x Err %08x\n", atomic_read(&tgtp->xmt_ls_rsp_aborted), atomic_read(&tgtp->xmt_ls_rsp_xb_set), atomic_read(&tgtp->xmt_ls_rsp_error)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "FCP: Rcv %08x Defer %08x Release %08x " "Drop %08x\n", atomic_read(&tgtp->rcv_fcp_cmd_in), @@ -1087,13 +1089,13 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) if (atomic_read(&tgtp->rcv_fcp_cmd_in) != atomic_read(&tgtp->rcv_fcp_cmd_out)) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Rcv FCP: in %08x != out %08x\n", atomic_read(&tgtp->rcv_fcp_cmd_in), atomic_read(&tgtp->rcv_fcp_cmd_out)); } - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "FCP Rsp: read %08x readrsp %08x " "write %08x rsp %08x\n", atomic_read(&tgtp->xmt_fcp_read), @@ -1101,31 +1103,31 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) atomic_read(&tgtp->xmt_fcp_write), atomic_read(&tgtp->xmt_fcp_rsp)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "FCP Rsp Cmpl: %08x err %08x drop %08x\n", atomic_read(&tgtp->xmt_fcp_rsp_cmpl), atomic_read(&tgtp->xmt_fcp_rsp_error), atomic_read(&tgtp->xmt_fcp_rsp_drop)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "FCP Rsp Abort: %08x xb %08x xricqe %08x\n", atomic_read(&tgtp->xmt_fcp_rsp_aborted), atomic_read(&tgtp->xmt_fcp_rsp_xb_set), atomic_read(&tgtp->xmt_fcp_xri_abort_cqe)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "ABORT: Xmt %08x Cmpl %08x\n", atomic_read(&tgtp->xmt_fcp_abort), atomic_read(&tgtp->xmt_fcp_abort_cmpl)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "ABORT: Sol %08x Usol %08x Err %08x Cmpl %08x", atomic_read(&tgtp->xmt_abort_sol), atomic_read(&tgtp->xmt_abort_unsol), atomic_read(&tgtp->xmt_abort_rsp), atomic_read(&tgtp->xmt_abort_rsp_error)); - len += snprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "\n"); cnt = 0; spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); @@ -1136,7 +1138,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) } spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); if (cnt) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "ABORT: %d ctx entries\n", cnt); spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_for_each_entry_safe(ctxp, next_ctxp, @@ -1144,7 +1146,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) list) { if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) break; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Entry: oxid %x state %x " "flag %x\n", ctxp->oxid, ctxp->state, @@ -1158,7 +1160,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) tot += atomic_read(&tgtp->xmt_fcp_release); tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "IO_CTX: %08x WAIT: cur %08x tot %08x\n" "CTX Outstanding %08llx\n", phba->sli4_hba.nvmet_xri_cnt, @@ -1176,10 +1178,10 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) if (!lport) return len; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "\nNVME HDWQ Statistics\n"); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "LS: Xmt %016x Cmpl %016x\n", atomic_read(&lport->fc4NvmeLsRequests), atomic_read(&lport->fc4NvmeLsCmpls)); @@ -1199,20 +1201,20 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) if (i >= 32) continue; - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "HDWQ (%d): Rd %016llx Wr %016llx " "IO %016llx ", i, data1, data2, data3); - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Cmpl %016llx OutIO %016llx\n", tot, ((data1 + data2 + data3) - tot)); } - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Total FCP Cmpl %016llx Issue %016llx " "OutIO %016llx\n", totin, totout, totout - totin); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "LS Xmt Err: Abrt %08x Err %08x " "Cmpl Err: xb %08x Err %08x\n", atomic_read(&lport->xmt_ls_abort), @@ -1220,7 +1222,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) atomic_read(&lport->cmpl_ls_xb), atomic_read(&lport->cmpl_ls_err)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "FCP Xmt Err: noxri %06x nondlp %06x " "qdepth %06x wqerr %06x err %06x Abrt %06x\n", atomic_read(&lport->xmt_fcp_noxri), @@ -1230,7 +1232,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) atomic_read(&lport->xmt_fcp_err), atomic_read(&lport->xmt_fcp_abort)); - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "FCP Cmpl Err: xb %08x Err %08x\n", atomic_read(&lport->cmpl_fcp_xb), atomic_read(&lport->cmpl_fcp_err)); @@ -1322,58 +1324,58 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) if (phba->nvmet_support == 0) { /* NVME Initiator */ - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "ktime %s: Total Samples: %lld\n", (phba->ktime_on ? "Enabled" : "Disabled"), phba->ktime_data_samples); if (phba->ktime_data_samples == 0) return len; - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "Segment 1: Last NVME Cmd cmpl " "done -to- Start of next NVME cnd (in driver)\n"); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg1_total, phba->ktime_data_samples), phba->ktime_seg1_min, phba->ktime_seg1_max); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "Segment 2: Driver start of NVME cmd " "-to- Firmware WQ doorbell\n"); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg2_total, phba->ktime_data_samples), phba->ktime_seg2_min, phba->ktime_seg2_max); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "Segment 3: Firmware WQ doorbell -to- " "MSI-X ISR cmpl\n"); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg3_total, phba->ktime_data_samples), phba->ktime_seg3_min, phba->ktime_seg3_max); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "Segment 4: MSI-X ISR cmpl -to- " "NVME cmpl done\n"); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg4_total, phba->ktime_data_samples), phba->ktime_seg4_min, phba->ktime_seg4_max); - len += snprintf( + len += scnprintf( buf + len, PAGE_SIZE - len, "Total IO avg time: %08lld\n", div_u64(phba->ktime_seg1_total + @@ -1385,7 +1387,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) } /* NVME Target */ - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "ktime %s: Total Samples: %lld %lld\n", (phba->ktime_on ? "Enabled" : "Disabled"), phba->ktime_data_samples, @@ -1393,46 +1395,46 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) if (phba->ktime_data_samples == 0) return len; - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 1: MSI-X ISR Rcv cmd -to- " "cmd pass to NVME Layer\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg1_total, phba->ktime_data_samples), phba->ktime_seg1_min, phba->ktime_seg1_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 2: cmd pass to NVME Layer- " "-to- Driver rcv cmd OP (action)\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg2_total, phba->ktime_data_samples), phba->ktime_seg2_min, phba->ktime_seg2_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 3: Driver rcv cmd OP -to- " "Firmware WQ doorbell: cmd\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg3_total, phba->ktime_data_samples), phba->ktime_seg3_min, phba->ktime_seg3_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 4: Firmware WQ doorbell: cmd " "-to- MSI-X ISR for cmd cmpl\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg4_total, phba->ktime_data_samples), phba->ktime_seg4_min, phba->ktime_seg4_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 5: MSI-X ISR for cmd cmpl " "-to- NVME layer passed cmd done\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg5_total, phba->ktime_data_samples), @@ -1440,10 +1442,10 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) phba->ktime_seg5_max); if (phba->ktime_status_samples == 0) { - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Total: cmd received by MSI-X ISR " "-to- cmd completed on wire\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld " "max %08lld\n", div_u64(phba->ktime_seg10_total, @@ -1453,46 +1455,46 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) return len; } - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 6: NVME layer passed cmd done " "-to- Driver rcv rsp status OP\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg6_total, phba->ktime_status_samples), phba->ktime_seg6_min, phba->ktime_seg6_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 7: Driver rcv rsp status OP " "-to- Firmware WQ doorbell: status\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg7_total, phba->ktime_status_samples), phba->ktime_seg7_min, phba->ktime_seg7_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 8: Firmware WQ doorbell: status" " -to- MSI-X ISR for status cmpl\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg8_total, phba->ktime_status_samples), phba->ktime_seg8_min, phba->ktime_seg8_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Segment 9: MSI-X ISR for status cmpl " "-to- NVME layer passed status done\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg9_total, phba->ktime_status_samples), phba->ktime_seg9_min, phba->ktime_seg9_max); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "Total: cmd received by MSI-X ISR -to- " "cmd completed on wire\n"); - len += snprintf(buf + len, PAGE_SIZE-len, + len += scnprintf(buf + len, PAGE_SIZE-len, "avg:%08lld min:%08lld max %08lld\n", div_u64(phba->ktime_seg10_total, phba->ktime_status_samples), @@ -1527,7 +1529,7 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) (phba->nvmeio_trc_size - 1); skip = phba->nvmeio_trc_output_idx; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "%s IO Trace %s: next_idx %d skip %d size %d\n", (phba->nvmet_support ? "NVME" : "NVMET"), (state ? "Enabled" : "Disabled"), @@ -1549,18 +1551,18 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) if (!dtp->fmt) continue; - len += snprintf(buf + len, size - len, dtp->fmt, + len += scnprintf(buf + len, size - len, dtp->fmt, dtp->data1, dtp->data2, dtp->data3); if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) { phba->nvmeio_trc_output_idx = 0; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Trace Complete\n"); goto out; } if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Trace Continue (%d of %d)\n", phba->nvmeio_trc_output_idx, phba->nvmeio_trc_size); @@ -1578,18 +1580,18 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) if (!dtp->fmt) continue; - len += snprintf(buf + len, size - len, dtp->fmt, + len += scnprintf(buf + len, size - len, dtp->fmt, dtp->data1, dtp->data2, dtp->data3); if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) { phba->nvmeio_trc_output_idx = 0; - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Trace Complete\n"); goto out; } if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) { - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Trace Continue (%d of %d)\n", phba->nvmeio_trc_output_idx, phba->nvmeio_trc_size); @@ -1597,7 +1599,7 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) } } - len += snprintf(buf + len, size - len, + len += scnprintf(buf + len, size - len, "Trace Done\n"); out: return len; @@ -1627,17 +1629,17 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size) uint32_t tot_rcv; uint32_t tot_cmpl; - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "CPUcheck %s ", (phba->cpucheck_on & LPFC_CHECK_NVME_IO ? "Enabled" : "Disabled")); if (phba->nvmet_support) { - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV ? "Rcv Enabled\n" : "Rcv Disabled\n")); } else { - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); } max_cnt = size - LPFC_DEBUG_OUT_LINE_SZ; @@ -1658,7 +1660,7 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size) if (!tot_xmt && !tot_cmpl && !tot_rcv) continue; - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "HDWQ %03d: ", i); for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { /* Only display non-zero counters */ @@ -1667,22 +1669,22 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size) !qp->cpucheck_rcv_io[j]) continue; if (phba->nvmet_support) { - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "CPU %03d: %x/%x/%x ", j, qp->cpucheck_rcv_io[j], qp->cpucheck_xmt_io[j], qp->cpucheck_cmpl_io[j]); } else { - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "CPU %03d: %x/%x ", j, qp->cpucheck_xmt_io[j], qp->cpucheck_cmpl_io[j]); } } - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Total: %x\n", tot_xmt); if (len >= max_cnt) { - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "Truncated ...\n"); return len; } @@ -2258,28 +2260,29 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, int cnt = 0; if (dent == phba->debug_writeGuard) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); else if (dent == phba->debug_writeApp) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); else if (dent == phba->debug_writeRef) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); else if (dent == phba->debug_readGuard) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); else if (dent == phba->debug_readApp) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); else if (dent == phba->debug_readRef) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); else if (dent == phba->debug_InjErrNPortID) - cnt = snprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid); + cnt = scnprintf(cbuf, 32, "0x%06x\n", + phba->lpfc_injerr_nportid); else if (dent == phba->debug_InjErrWWPN) { memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); tmp = cpu_to_be64(tmp); - cnt = snprintf(cbuf, 32, "0x%016llx\n", tmp); + cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp); } else if (dent == phba->debug_InjErrLBA) { if (phba->lpfc_injerr_lba == (sector_t)(-1)) - cnt = snprintf(cbuf, 32, "off\n"); + cnt = scnprintf(cbuf, 32, "off\n"); else - cnt = snprintf(cbuf, 32, "0x%llx\n", + cnt = scnprintf(cbuf, 32, "0x%llx\n", (uint64_t) phba->lpfc_injerr_lba); } else lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -3224,17 +3227,17 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, switch (count) { case SIZE_U8: /* byte (8 bits) */ pci_read_config_byte(pdev, where, &u8val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%03x: %02x\n", where, u8val); break; case SIZE_U16: /* word (16 bits) */ pci_read_config_word(pdev, where, &u16val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%03x: %04x\n", where, u16val); break; case SIZE_U32: /* double word (32 bits) */ pci_read_config_dword(pdev, where, &u32val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%03x: %08x\n", where, u32val); break; case LPFC_PCI_CFG_BROWSE: /* browse all */ @@ -3254,25 +3257,25 @@ pcicfg_browse: offset = offset_label; /* Read PCI config space */ - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%03x: ", offset_label); while (index > 0) { pci_read_config_dword(pdev, offset, &u32val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%08x ", u32val); offset += sizeof(uint32_t); if (offset >= LPFC_PCI_CFG_SIZE) { - len += snprintf(pbuffer+len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "\n"); break; } index -= sizeof(uint32_t); if (!index) - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "\n"); else if (!(index % (8 * sizeof(uint32_t)))) { offset_label += (8 * sizeof(uint32_t)); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "\n%03x: ", offset_label); } } @@ -3543,7 +3546,7 @@ lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes, if (acc_range == SINGLE_WORD) { offset_run = offset; u32val = readl(mem_mapped_bar + offset_run); - len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "%05x: %08x\n", offset_run, u32val); } else goto baracc_browse; @@ -3557,35 +3560,35 @@ baracc_browse: offset_run = offset_label; /* Read PCI bar memory mapped space */ - len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "%05x: ", offset_label); index = LPFC_PCI_BAR_RD_SIZE; while (index > 0) { u32val = readl(mem_mapped_bar + offset_run); - len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "%08x ", u32val); offset_run += sizeof(uint32_t); if (acc_range == LPFC_PCI_BAR_BROWSE) { if (offset_run >= bar_size) { - len += snprintf(pbuffer+len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); break; } } else { if (offset_run >= offset + (acc_range * sizeof(uint32_t))) { - len += snprintf(pbuffer+len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); break; } } index -= sizeof(uint32_t); if (!index) - len += snprintf(pbuffer+len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); else if (!(index % (8 * sizeof(uint32_t)))) { offset_label += (8 * sizeof(uint32_t)); - len += snprintf(pbuffer+len, + len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n%05x: ", offset_label); } @@ -3758,19 +3761,19 @@ __lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype, if (!qp) return len; - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\t\t%s WQ info: ", wqtype); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "AssocCQID[%04d]: WQ-STAT[oflow:x%x posted:x%llx]\n", qp->assoc_qid, qp->q_cnt_1, (unsigned long long)qp->q_cnt_4); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\t\tWQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]", qp->queue_id, qp->entry_count, qp->entry_size, qp->host_index, qp->hba_index, qp->notify_interval); - len += snprintf(pbuffer + len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); return len; } @@ -3810,21 +3813,22 @@ __lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype, if (!qp) return len; - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\t%s CQ info: ", cqtype); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "AssocEQID[%02d]: CQ STAT[max:x%x relw:x%x " "xabt:x%x wq:x%llx]\n", qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3, (unsigned long long)qp->q_cnt_4); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\tCQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " "HST-IDX[%04d], NTFI[%03d], PLMT[%03d]", qp->queue_id, qp->entry_count, qp->entry_size, qp->host_index, qp->notify_interval, qp->max_proc_limit); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + "\n"); return len; } @@ -3836,19 +3840,19 @@ __lpfc_idiag_print_rqpair(struct lpfc_queue *qp, struct lpfc_queue *datqp, if (!qp || !datqp) return len; - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\t\t%s RQ info: ", rqtype); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "AssocCQID[%02d]: RQ-STAT[nopost:x%x nobuf:x%x " "posted:x%x rcv:x%llx]\n", qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3, (unsigned long long)qp->q_cnt_4); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\t\tHQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n", qp->queue_id, qp->entry_count, qp->entry_size, qp->host_index, qp->hba_index, qp->notify_interval); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\t\tDQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n", datqp->queue_id, datqp->entry_count, @@ -3927,18 +3931,19 @@ __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype, if (!qp) return len; - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n%s EQ info: EQ-STAT[max:x%x noE:x%x " "cqe_proc:x%x eqe_proc:x%llx eqd %d]\n", eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3, (unsigned long long)qp->q_cnt_4, qp->q_mode); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "EQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " "HST-IDX[%04d], NTFI[%03d], PLMT[%03d], AFFIN[%03d]", qp->queue_id, qp->entry_count, qp->entry_size, qp->host_index, qp->notify_interval, qp->max_proc_limit, qp->chann); - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, + "\n"); return len; } @@ -3991,9 +3996,10 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, if (phba->lpfc_idiag_last_eq >= phba->cfg_hdw_queue) phba->lpfc_idiag_last_eq = 0; - len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, - "HDWQ %d out of %d HBA HDWQs\n", - x, phba->cfg_hdw_queue); + len += scnprintf(pbuffer + len, + LPFC_QUE_INFO_GET_BUF_SIZE - len, + "HDWQ %d out of %d HBA HDWQs\n", + x, phba->cfg_hdw_queue); /* Fast-path EQ */ qp = phba->sli4_hba.hdwq[x].hba_eq; @@ -4075,7 +4081,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); too_big: - len += snprintf(pbuffer + len, + len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n"); out: spin_unlock_irq(&phba->hbalock); @@ -4131,22 +4137,22 @@ lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, return 0; esize = pque->entry_size; - len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "QE-INDEX[%04d]:\n", index); offset = 0; - pentry = pque->qe[index].address; + pentry = lpfc_sli4_qe(pque, index); while (esize > 0) { - len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "%08x ", *pentry); pentry++; offset += sizeof(uint32_t); esize -= sizeof(uint32_t); if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) - len += snprintf(pbuffer+len, + len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); } - len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); return len; } @@ -4485,7 +4491,7 @@ pass_check: pque = (struct lpfc_queue *)idiag.ptr_private; if (offset > pque->entry_size/sizeof(uint32_t) - 1) goto error_out; - pentry = pque->qe[index].address; + pentry = lpfc_sli4_qe(pque, index); pentry += offset; if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR) *pentry = value; @@ -4506,7 +4512,7 @@ error_out: * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register * @phba: The pointer to hba structure. * @pbuffer: The pointer to the buffer to copy the data to. - * @len: The lenght of bytes to copied. + * @len: The length of bytes to copied. * @drbregid: The id to doorbell registers. * * Description: @@ -4526,27 +4532,27 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, switch (drbregid) { case LPFC_DRB_EQ: - len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(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, + len += scnprintf(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, + len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, "MQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.MQDBregaddr)); break; case LPFC_DRB_WQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, "WQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.WQDBregaddr)); break; case LPFC_DRB_RQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, "RQ-DRB-REG: 0x%08x\n", readl(phba->sli4_hba.RQDBregaddr)); break; @@ -4716,7 +4722,7 @@ error_out: * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers * @phba: The pointer to hba structure. * @pbuffer: The pointer to the buffer to copy the data to. - * @len: The lenght of bytes to copied. + * @len: The length of bytes to copied. * @drbregid: The id to doorbell registers. * * Description: @@ -4736,37 +4742,37 @@ lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer, switch (ctlregid) { case LPFC_CTL_PORT_SEM: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, "Port SemReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_SEM_OFFSET)); break; case LPFC_CTL_PORT_STA: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, "Port StaReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_STA_OFFSET)); break; case LPFC_CTL_PORT_CTL: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, "Port CtlReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_CTL_OFFSET)); break; case LPFC_CTL_PORT_ER1: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, "Port Er1Reg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_ER1_OFFSET)); break; case LPFC_CTL_PORT_ER2: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, "Port Er2Reg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PORT_ER2_OFFSET)); break; case LPFC_CTL_PDEV_CTL: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, "PDev CtlReg: 0x%08x\n", readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET)); @@ -4959,13 +4965,13 @@ lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer) mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, "mbx_dump_map: 0x%08x\n", mbx_dump_map); - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, "mbx_dump_cnt: %04d\n", mbx_dump_cnt); - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, "mbx_word_cnt: %04d\n", mbx_word_cnt); - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd); return len; @@ -5114,35 +5120,35 @@ lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) { uint16_t ext_cnt, ext_size; - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\nAvailable Extents Information:\n"); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tPort Available VPI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI, &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Count %3d, Size %3d\n", ext_cnt, ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tPort Available VFI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI, &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Count %3d, Size %3d\n", ext_cnt, ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tPort Available RPI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI, &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Count %3d, Size %3d\n", ext_cnt, ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tPort Available XRI extents: "); lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI, &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Count %3d, Size %3d\n", ext_cnt, ext_size); return len; @@ -5166,55 +5172,55 @@ lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) uint16_t ext_cnt, ext_size; int rc; - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\nAllocated Extents Information:\n"); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tHost Allocated VPI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI, &ext_cnt, &ext_size); if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "N/A\n"); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tHost Allocated VFI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI, &ext_cnt, &ext_size); if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "N/A\n"); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tHost Allocated RPI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI, &ext_cnt, &ext_size); if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "N/A\n"); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tHost Allocated XRI extents: "); rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI, &ext_cnt, &ext_size); if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "Port %d Extent %3d, Size %3d\n", phba->brd_no, ext_cnt, ext_size); else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "N/A\n"); return len; @@ -5238,49 +5244,49 @@ lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) struct lpfc_rsrc_blks *rsrc_blks; int index; - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\nDriver Extents Information:\n"); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tVPI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); index++; } - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tVFI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list, list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); index++; } - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tRPI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list, list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); index++; } - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\tXRI extents:\n"); index = 0; list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list, list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, + len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\t\tBlock %3d: Start %4d, Count %4d\n", index, rsrc_blks->rsrc_start, rsrc_blks->rsrc_size); @@ -5706,11 +5712,11 @@ lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp, if (i != 0) pr_err("%s\n", line_buf); len = 0; - len += snprintf(line_buf+len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, "%03d: ", i); } - len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, "%08x ", (uint32_t)*pword); pword++; } @@ -5773,11 +5779,11 @@ lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) pr_err("%s\n", line_buf); len = 0; memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); - len += snprintf(line_buf+len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, "%03d: ", i); } - len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, "%08x ", ((uint32_t)*pword) & 0xffffffff); pword++; @@ -5796,18 +5802,18 @@ lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) pr_err("%s\n", line_buf); len = 0; memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); - len += snprintf(line_buf+len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, "%03d: ", i); } for (j = 0; j < 4; j++) { - len += snprintf(line_buf+len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, "%02x", ((uint8_t)*pbyte) & 0xff); pbyte++; } - len += snprintf(line_buf+len, + len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, " "); } if ((i - 1) % 8) @@ -5891,7 +5897,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) phba, &lpfc_debugfs_op_lockstat); if (!phba->debug_lockstat) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0913 Cant create debugfs lockstat\n"); + "4610 Cant create debugfs lockstat\n"); goto debug_failed; } #endif @@ -6134,7 +6140,7 @@ nvmeio_off: vport, &lpfc_debugfs_op_scsistat); if (!vport->debug_scsistat) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0914 Cannot create debugfs scsistat\n"); + "4611 Cannot create debugfs scsistat\n"); goto debug_failed; } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 93ab7dfb8ee0..2322ddb085c0 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -345,10 +345,10 @@ lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx) esize = q->entry_size; qe_word_cnt = esize / sizeof(uint32_t); - pword = q->qe[idx].address; + pword = lpfc_sli4_qe(q, idx); len = 0; - len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx); + len += scnprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx); if (qe_word_cnt > 8) printk(KERN_ERR "%s\n", line_buf); @@ -359,11 +359,11 @@ lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx) if (qe_word_cnt > 8) { len = 0; memset(line_buf, 0, LPFC_LBUF_SZ); - len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, + len += scnprintf(line_buf+len, LPFC_LBUF_SZ-len, "%03d: ", i); } } - len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ", + len += scnprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ", ((uint32_t)*pword) & 0xffffffff); pword++; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index fc077cb87900..f12780f4cfbb 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -30,6 +30,8 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_fc.h> +#include <uapi/scsi/fc/fc_fs.h> +#include <uapi/scsi/fc/fc_els.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -1961,7 +1963,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp; struct lpfc_dmabuf *prsp; - int disc, rc; + int disc; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -1990,7 +1992,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); - rc = 0; /* PLOGI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -2029,18 +2030,16 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) - rc = NLP_STE_FREED_NODE; - else - rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PLOGI); + if (!lpfc_error_lost_link(irsp)) + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_CMPL_PLOGI); } else { /* Good status, call state machine */ prsp = list_entry(((struct lpfc_dmabuf *) cmdiocb->context2)->list.next, struct lpfc_dmabuf, list); ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); - rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, + lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); } @@ -3082,6 +3081,116 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) } /** + * lpfc_issue_els_rscn - Issue an RSCN to the Fabric Controller (Fabric) + * or the other nport (pt2pt). + * @vport: pointer to a host virtual N_Port data structure. + * @retry: number of retries to the command IOCB. + * + * This routine issues a RSCN to the Fabric Controller (DID 0xFFFFFD) + * when connected to a fabric, or to the remote port when connected + * in point-to-point mode. When sent to the Fabric Controller, it will + * replay the RSCN to registered recipients. + * + * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp + * will be incremented by 1 for holding the ndlp and the reference to ndlp + * will be stored into the context1 field of the IOCB for the completion + * callback function to the RSCN ELS command. + * + * Return code + * 0 - Successfully issued RSCN command + * 1 - Failed to issue RSCN command + **/ +int +lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_nodelist *ndlp; + struct { + struct fc_els_rscn rscn; + struct fc_els_rscn_page portid; + } *event; + uint32_t nportid; + uint16_t cmdsize = sizeof(*event); + + /* Not supported for private loop */ + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && + !(vport->fc_flag & FC_PUBLIC_LOOP)) + return 1; + + if (vport->fc_flag & FC_PT2PT) { + /* find any mapped nport - that would be the other nport */ + ndlp = lpfc_findnode_mapped(vport); + if (!ndlp) + return 1; + } else { + nportid = FC_FID_FCTRL; + /* find the fabric controller node */ + ndlp = lpfc_findnode_did(vport, nportid); + if (!ndlp) { + /* if one didn't exist, make one */ + ndlp = lpfc_nlp_init(vport, nportid); + if (!ndlp) + return 1; + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + return 1; + } + } + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_RSCN_XMT); + + if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ + lpfc_nlp_put(ndlp); + return 1; + } + + event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; + + event->rscn.rscn_cmd = ELS_RSCN; + event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page); + event->rscn.rscn_plen = cpu_to_be16(cmdsize); + + nportid = vport->fc_myDID; + /* appears that page flags must be 0 for fabric to broadcast RSCN */ + event->portid.rscn_page_flags = 0; + event->portid.rscn_fid[0] = (nportid & 0x00FF0000) >> 16; + event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8; + event->portid.rscn_fid[2] = nportid & 0x000000FF; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue RSCN: did:x%x", + ndlp->nlp_DID, 0, 0); + + phba->fc_stat.elsXmitRSCN++; + elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_nlp_put(ndlp); + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + /* This will cause the callback-function lpfc_cmpl_els_cmd to + * trigger the release of node. + */ + if (!(vport->fc_flag & FC_PT2PT)) + lpfc_nlp_put(ndlp); + + return 0; +} + +/** * lpfc_issue_els_farpr - Issue a farp to an node on a vport * @vport: pointer to a host virtual N_Port data structure. * @nportid: N_Port identifier to the remote node. @@ -4199,6 +4308,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((rspiocb->iocb.ulpStatus == 0) && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { if (!lpfc_unreg_rpi(vport, ndlp) && + (!(vport->fc_flag & FC_PT2PT)) && (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) { lpfc_printf_vlog(vport, KERN_INFO, @@ -6217,6 +6327,8 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) continue; } + if (ndlp->nlp_fc4_type & NLP_FC4_NVME) + lpfc_nvme_rescan_port(vport, ndlp); lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); @@ -6321,6 +6433,19 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_RSCN, lp[i]); + /* Check if RSCN is coming from a direct-connected remote NPort */ + if (vport->fc_flag & FC_PT2PT) { + /* If so, just ACC it, no other action needed for now */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "2024 pt2pt RSCN %08x Data: x%x x%x\n", + *lp, vport->fc_flag, payload_len); + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + + if (ndlp->nlp_fc4_type & NLP_FC4_NVME) + lpfc_nvme_rescan_port(vport, ndlp); + return 0; + } + /* If we are about to begin discovery, just ACC the RSCN. * Discovery processing will satisfy it. */ @@ -6744,12 +6869,11 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint32_t *lp; RNID *rn; struct ls_rjt stat; - uint32_t cmd; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; - cmd = *lp++; + lp++; rn = (RNID *) lp; /* RNID received */ @@ -7338,7 +7462,10 @@ int lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq) { struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport, - rrq->nlp_DID); + rrq->nlp_DID); + if (!ndlp) + return 1; + if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag)) return lpfc_issue_els_rrq(rrq->vport, ndlp, rrq->nlp_DID, rrq); @@ -7508,14 +7635,14 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint32_t *lp; IOCB_t *icmd; FARP *fp; - uint32_t cmd, cnt, did; + uint32_t cnt, did; icmd = &cmdiocb->iocb; did = icmd->un.elsreq64.remoteID; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; - cmd = *lp++; + lp++; fp = (FARP *) lp; /* FARP-REQ received from DID <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -7580,14 +7707,14 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *pcmd; uint32_t *lp; IOCB_t *icmd; - uint32_t cmd, did; + uint32_t did; icmd = &cmdiocb->iocb; did = icmd->un.elsreq64.remoteID; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; - cmd = *lp++; + lp++; /* FARP-RSP received from DID <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0600 FARP-RSP received from DID x%x\n", did); @@ -8454,6 +8581,14 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_INVALID_OX_RX; break; + case ELS_CMD_FPIN: + /* + * Received FPIN from fabric - pass it to the + * transport FPIN handler. + */ + fc_host_fpin_rcv(shost, elsiocb->iocb.unsli3.rcvsli3.acc_len, + (char *)payload); + break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", @@ -8775,7 +8910,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_nlp_put(ndlp); return; } - + /* fall through */ default: /* Try to recover from this error */ if (phba->sli_rev == LPFC_SLI_REV4) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index aa4961a2caf8..28ecaa7fc715 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -885,15 +885,9 @@ lpfc_linkdown(struct lpfc_hba *phba) LPFC_MBOXQ_t *mb; int i; - if (phba->link_state == LPFC_LINK_DOWN) { - if (phba->sli4_hba.conf_trunk) { - phba->trunk_link.link0.state = 0; - phba->trunk_link.link1.state = 0; - phba->trunk_link.link2.state = 0; - phba->trunk_link.link3.state = 0; - } + if (phba->link_state == LPFC_LINK_DOWN) return 0; - } + /* Block all SCSI stack I/Os */ lpfc_scsi_dev_block(phba); @@ -932,7 +926,11 @@ lpfc_linkdown(struct lpfc_hba *phba) } } lpfc_destroy_vport_work_array(phba, vports); - /* Clean up any firmware default rpi's */ + + /* Clean up any SLI3 firmware default rpi's */ + if (phba->sli_rev > LPFC_SLI_REV3) + goto skip_unreg_did; + mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb); @@ -944,6 +942,7 @@ lpfc_linkdown(struct lpfc_hba *phba) } } + skip_unreg_did: /* Setup myDID for link up if we are in pt2pt mode */ if (phba->pport->fc_flag & FC_PT2PT) { mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -4147,9 +4146,15 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rdata->pnode = lpfc_nlp_get(ndlp); if (ndlp->nlp_type & NLP_FCP_TARGET) - rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; + rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET; if (ndlp->nlp_type & NLP_FCP_INITIATOR) - rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; + rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; + if (ndlp->nlp_type & NLP_NVME_INITIATOR) + rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR; + if (ndlp->nlp_type & NLP_NVME_TARGET) + rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET; + if (ndlp->nlp_type & NLP_NVME_DISCOVERY) + rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY; if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) fc_remote_port_rolechg(rport, rport_ids.roles); @@ -4667,12 +4672,15 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, case CMD_GEN_REQUEST64_CR: if (iocb->context_un.ndlp == ndlp) return 1; + /* fall through */ case CMD_ELS_REQUEST64_CR: if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) return 1; + /* fall through */ case CMD_XMIT_ELS_RSP64_CX: if (iocb->context1 == (uint8_t *) ndlp) return 1; + /* fall through */ } } else if (pring->ringno == LPFC_FCP_RING) { /* Skip match check if waiting to relogin to FCP target */ @@ -4868,6 +4876,10 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * accept PLOGIs after unreg_rpi_cmpl */ acc_plogi = 0; + } else if (vport->load_flag & FC_UNLOADING) { + mbox->ctx_ndlp = NULL; + mbox->mbox_cmpl = + lpfc_sli_def_mbox_cmpl; } else { mbox->ctx_ndlp = ndlp; mbox->mbox_cmpl = @@ -4979,6 +4991,10 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) LPFC_MBOXQ_t *mbox; int rc; + /* Unreg DID is an SLI3 operation. */ + if (phba->sli_rev > LPFC_SLI_REV3) + return; + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS, @@ -5261,6 +5277,41 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) } struct lpfc_nodelist * +lpfc_findnode_mapped(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_nodelist *ndlp; + uint32_t data1; + unsigned long iflags; + + spin_lock_irqsave(shost->host_lock, iflags); + + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || + ndlp->nlp_state == NLP_STE_MAPPED_NODE) { + data1 = (((uint32_t)ndlp->nlp_state << 24) | + ((uint32_t)ndlp->nlp_xri << 16) | + ((uint32_t)ndlp->nlp_type << 8) | + ((uint32_t)ndlp->nlp_rpi & 0xff)); + spin_unlock_irqrestore(shost->host_lock, iflags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "2025 FIND node DID " + "Data: x%p x%x x%x x%x %p\n", + ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, data1, + ndlp->active_rrqs_xri_bitmap); + return ndlp; + } + } + spin_unlock_irqrestore(shost->host_lock, iflags); + + /* FIND node did <did> NOT FOUND */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "2026 FIND mapped did NOT FOUND.\n"); + return NULL; +} + +struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); @@ -5856,7 +5907,7 @@ restart_disc: case LPFC_LINK_UP: lpfc_issue_clear_la(phba, vport); - /* Drop thru */ + /* fall through */ case LPFC_LINK_UNKNOWN: case LPFC_WARM_START: case LPFC_INIT_START: diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index ec1227018913..5b439a6dcde1 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -560,6 +560,8 @@ struct fc_vft_header { #define fc_vft_hdr_hopct_WORD word1 }; +#include <uapi/scsi/fc/fc_els.h> + /* * Extended Link Service LS_COMMAND codes (Payload Word 0) */ @@ -599,10 +601,12 @@ struct fc_vft_header { #define ELS_CMD_RPL 0x57000000 #define ELS_CMD_FAN 0x60000000 #define ELS_CMD_RSCN 0x61040000 +#define ELS_CMD_RSCN_XMT 0x61040008 #define ELS_CMD_SCR 0x62000000 #define ELS_CMD_RNID 0x78000000 #define ELS_CMD_LIRR 0x7A000000 #define ELS_CMD_LCB 0x81000000 +#define ELS_CMD_FPIN 0x16000000 #else /* __LITTLE_ENDIAN_BITFIELD */ #define ELS_CMD_MASK 0xffff #define ELS_RSP_MASK 0xff @@ -639,10 +643,12 @@ struct fc_vft_header { #define ELS_CMD_RPL 0x57 #define ELS_CMD_FAN 0x60 #define ELS_CMD_RSCN 0x0461 +#define ELS_CMD_RSCN_XMT 0x08000461 #define ELS_CMD_SCR 0x62 #define ELS_CMD_RNID 0x78 #define ELS_CMD_LIRR 0x7A #define ELS_CMD_LCB 0x81 +#define ELS_CMD_FPIN ELS_FPIN #endif /* diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index ff875b833192..77f9a55a3f54 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1894,18 +1894,19 @@ struct lpfc_mbx_set_link_diag_loopback { union { struct { uint32_t word0; -#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0 -#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003 -#define lpfc_mbx_set_diag_lpbk_type_WORD word0 -#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0 -#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1 -#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2 -#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16 -#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F -#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0 -#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22 -#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003 -#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0 +#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0 +#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003 +#define lpfc_mbx_set_diag_lpbk_type_WORD word0 +#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0 +#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1 +#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2 +#define LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED 0x3 +#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16 +#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F +#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0 +#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22 +#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003 +#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0 } req; struct { uint32_t word0; @@ -4083,22 +4084,7 @@ struct lpfc_acqe_grp5 { uint32_t trailer; }; -static char *const trunk_errmsg[] = { /* map errcode */ - "", /* There is no such error code at index 0*/ - "link negotiated speed does not match existing" - " trunk - link was \"low\" speed", - "link negotiated speed does not match" - " existing trunk - link was \"middle\" speed", - "link negotiated speed does not match existing" - " trunk - link was \"high\" speed", - "Attached to non-trunking port - F_Port", - "Attached to non-trunking port - N_Port", - "FLOGI response timeout", - "non-FLOGI frame received", - "Invalid FLOGI response", - "Trunking initialization protocol", - "Trunk peer device mismatch", -}; +extern const char *const trunk_errmsg[]; struct lpfc_acqe_fc_la { uint32_t word0; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7fcdaed3fa94..faf43b1d3dbe 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -72,7 +72,7 @@ unsigned long _dump_buf_dif_order; spinlock_t _dump_buf_lock; /* Used when mapping IRQ vectors in a driver centric manner */ -uint32_t lpfc_present_cpu; +static uint32_t lpfc_present_cpu; static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); static int lpfc_post_rcv_buf(struct lpfc_hba *); @@ -93,8 +93,8 @@ static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *); static void lpfc_sli4_disable_intr(struct lpfc_hba *); static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t); static void lpfc_sli4_oas_verify(struct lpfc_hba *phba); -static uint16_t lpfc_find_eq_handle(struct lpfc_hba *, uint16_t); static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int); +static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *); static struct scsi_transport_template *lpfc_transport_template = NULL; static struct scsi_transport_template *lpfc_vport_transport_template = NULL; @@ -1117,19 +1117,19 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) } } + spin_unlock_irq(&phba->hbalock); if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_lock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_splice_init(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list, &nvmet_aborts); - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_unlock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_for_each_entry_safe(ctxp, ctxp_next, &nvmet_aborts, list) { ctxp->flag &= ~(LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP); lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); } } - spin_unlock_irq(&phba->hbalock); lpfc_sli4_free_sp_events(phba); return cnt; } @@ -1274,8 +1274,10 @@ lpfc_hb_eq_delay_work(struct work_struct *work) if (!eqcnt) goto requeue; + /* Loop thru all IRQ vectors */ for (i = 0; i < phba->cfg_irq_chann; i++) { - eq = phba->sli4_hba.hdwq[i].hba_eq; + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[i].eq; if (eq && eqcnt[eq->last_cpu] < 2) eqcnt[eq->last_cpu]++; continue; @@ -1844,8 +1846,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) /* If the pci channel is offline, ignore possible errors, since * we cannot communicate with the pci card anyway. */ - if (pci_channel_offline(phba->pcidev)) + if (pci_channel_offline(phba->pcidev)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3166 pci channel is offline\n"); + lpfc_sli4_offline_eratt(phba); return; + } memset(&portsmphr_reg, 0, sizeof(portsmphr_reg)); if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); @@ -1922,6 +1928,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3151 PCI bus read access failure: x%x\n", readl(phba->sli4_hba.u.if_type2.STATUSregaddr)); + lpfc_sli4_offline_eratt(phba); return; } reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); @@ -2958,7 +2965,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) del_timer_sync(&phba->fcp_poll_timer); break; case LPFC_PCI_DEV_OC: - /* Stop any OneConnect device sepcific driver timers */ + /* Stop any OneConnect device specific driver timers */ lpfc_sli4_stop_fcf_redisc_wait_timer(phba); break; default: @@ -3075,7 +3082,7 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) * This routine moves a batch of XRIs from lpfc_io_buf_list_put of HWQ 0 * to expedite pool. Mark them as expedite. **/ -void lpfc_create_expedite_pool(struct lpfc_hba *phba) +static void lpfc_create_expedite_pool(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *qp; struct lpfc_io_buf *lpfc_ncmd; @@ -3110,7 +3117,7 @@ void lpfc_create_expedite_pool(struct lpfc_hba *phba) * This routine returns XRIs from expedite pool to lpfc_io_buf_list_put * of HWQ 0. Clear the mark. **/ -void lpfc_destroy_expedite_pool(struct lpfc_hba *phba) +static void lpfc_destroy_expedite_pool(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *qp; struct lpfc_io_buf *lpfc_ncmd; @@ -3230,7 +3237,7 @@ void lpfc_create_multixri_pools(struct lpfc_hba *phba) * * This routine returns XRIs from public/private to lpfc_io_buf_list_put. **/ -void lpfc_destroy_multixri_pools(struct lpfc_hba *phba) +static void lpfc_destroy_multixri_pools(struct lpfc_hba *phba) { u32 i; u32 hwq_count; @@ -3245,6 +3252,13 @@ void lpfc_destroy_multixri_pools(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) lpfc_destroy_expedite_pool(phba); + if (!(phba->pport->load_flag & FC_UNLOADING)) { + lpfc_sli_flush_fcp_rings(phba); + + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + lpfc_sli_flush_nvme_rings(phba); + } + hwq_count = phba->cfg_hdw_queue; for (i = 0; i < hwq_count; i++) { @@ -3611,8 +3625,6 @@ lpfc_io_free(struct lpfc_hba *phba) struct lpfc_sli4_hdw_queue *qp; int idx; - spin_lock_irq(&phba->hbalock); - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; /* Release all the lpfc_nvme_bufs maintained by this host. */ @@ -3642,8 +3654,6 @@ lpfc_io_free(struct lpfc_hba *phba) } spin_unlock(&qp->io_buf_list_get_lock); } - - spin_unlock_irq(&phba->hbalock); } /** @@ -4106,14 +4116,13 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) * pci bus space for an I/O. The DMA buffer includes the * number of SGE's necessary to support the sg_tablesize. */ - lpfc_ncmd->data = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool, - GFP_KERNEL, - &lpfc_ncmd->dma_handle); + lpfc_ncmd->data = dma_pool_zalloc(phba->lpfc_sg_dma_buf_pool, + GFP_KERNEL, + &lpfc_ncmd->dma_handle); if (!lpfc_ncmd->data) { kfree(lpfc_ncmd); break; } - memset(lpfc_ncmd->data, 0, phba->cfg_sg_dma_buf_size); /* * 4K Page alignment is CRITICAL to BlockGuard, double check @@ -4339,6 +4348,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0); + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) + lpfc_setup_bg(phba, shost); + error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); if (error) goto out_put_shost; @@ -4457,7 +4469,7 @@ finished: return stat; } -void lpfc_host_supported_speeds_set(struct Scsi_Host *shost) +static void lpfc_host_supported_speeds_set(struct Scsi_Host *shost) { struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_hba *phba = vport->phba; @@ -5047,7 +5059,7 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, bf_get(lpfc_acqe_fc_la_speed, acqe_fc)); phba->sli4_hba.link_state.logical_speed = - bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc); + bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10; /* We got FC link speed, convert to fc_linkspeed (READ_TOPOLOGY) */ phba->fc_linkspeed = lpfc_async_link_speed_to_read_top( @@ -5150,8 +5162,14 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) bf_get(lpfc_acqe_fc_la_port_number, acqe_fc); phba->sli4_hba.link_state.fault = bf_get(lpfc_acqe_link_fault, acqe_fc); - phba->sli4_hba.link_state.logical_speed = + + if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) == + LPFC_FC_LA_TYPE_LINK_DOWN) + phba->sli4_hba.link_state.logical_speed = 0; + else if (!phba->sli4_hba.conf_trunk) + phba->sli4_hba.link_state.logical_speed = bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2896 Async FC event - Speed:%dGBaud Topology:x%x " "LA Type:x%x Port Type:%d Port Number:%d Logical speed:" @@ -6543,6 +6561,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) spin_lock_init(&phba->sli4_hba.abts_nvmet_buf_list_lock); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_nvmet_io_wait_list); + spin_lock_init(&phba->sli4_hba.t_active_list_lock); + INIT_LIST_HEAD(&phba->sli4_hba.t_active_ctx_list); } /* This abort list used by worker thread */ @@ -7652,8 +7672,6 @@ lpfc_post_init_setup(struct lpfc_hba *phba) */ shost = pci_get_drvdata(phba->pcidev); shost->can_queue = phba->cfg_hba_queue_depth - 10; - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) - lpfc_setup_bg(phba, shost); lpfc_host_attrib_init(shost); @@ -8603,9 +8621,9 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) if (phba->nvmet_support) { if (phba->cfg_irq_chann < phba->cfg_nvmet_mrq) phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX) + phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX; } - if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX) - phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX; lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2574 IO channels: hdwQ %d IRQ %d MRQ: %d\n", @@ -8626,10 +8644,12 @@ static int lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx) { struct lpfc_queue *qdesc; + int cpu; + cpu = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ); qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, phba->sli4_hba.cq_esize, - LPFC_CQE_EXP_COUNT); + LPFC_CQE_EXP_COUNT, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0508 Failed allocate fast-path NVME CQ (%d)\n", @@ -8638,11 +8658,12 @@ lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx) } qdesc->qe_valid = 1; qdesc->hdwq = wqidx; - qdesc->chann = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ); + qdesc->chann = cpu; phba->sli4_hba.hdwq[wqidx].nvme_cq = qdesc; qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, - LPFC_WQE128_SIZE, LPFC_WQE_EXP_COUNT); + LPFC_WQE128_SIZE, LPFC_WQE_EXP_COUNT, + cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0509 Failed allocate fast-path NVME WQ (%d)\n", @@ -8661,18 +8682,20 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) { struct lpfc_queue *qdesc; uint32_t wqesize; + int cpu; + cpu = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ); /* Create Fast Path FCP CQs */ 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, - LPFC_CQE_EXP_COUNT); + LPFC_CQE_EXP_COUNT, cpu); else qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx); @@ -8680,7 +8703,7 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) } qdesc->qe_valid = 1; qdesc->hdwq = wqidx; - qdesc->chann = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ); + qdesc->chann = cpu; phba->sli4_hba.hdwq[wqidx].fcp_cq = qdesc; /* Create Fast Path FCP WQs */ @@ -8690,11 +8713,11 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize; qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, wqesize, - LPFC_WQE_EXP_COUNT); + LPFC_WQE_EXP_COUNT, cpu); } else qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.wq_esize, - phba->sli4_hba.wq_ecount); + phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8727,8 +8750,10 @@ int lpfc_sli4_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; - int idx, eqidx; + int idx, cpu, eqcpu; struct lpfc_sli4_hdw_queue *qp; + struct lpfc_vector_map_info *cpup; + struct lpfc_vector_map_info *eqcpup; struct lpfc_eq_intr_info *eqi; /* @@ -8813,40 +8838,60 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list); /* Create HBA Event Queues (EQs) */ - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { - /* - * If there are more Hardware Queues than available - * CQs, multiple Hardware Queues may share a common EQ. + for_each_present_cpu(cpu) { + /* We only want to create 1 EQ per vector, even though + * multiple CPUs might be using that vector. so only + * selects the CPUs that are LPFC_CPU_FIRST_IRQ. */ - if (idx >= phba->cfg_irq_chann) { - /* Share an existing EQ */ - eqidx = lpfc_find_eq_handle(phba, idx); - phba->sli4_hba.hdwq[idx].hba_eq = - phba->sli4_hba.hdwq[eqidx].hba_eq; + cpup = &phba->sli4_hba.cpu_map[cpu]; + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) continue; - } - /* Create an EQ */ + + /* Get a ptr to the Hardware Queue associated with this CPU */ + qp = &phba->sli4_hba.hdwq[cpup->hdwq]; + + /* Allocate an EQ */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.eq_esize, - phba->sli4_hba.eq_ecount); + phba->sli4_hba.eq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0497 Failed allocate EQ (%d)\n", idx); + "0497 Failed allocate EQ (%d)\n", + cpup->hdwq); goto out_error; } qdesc->qe_valid = 1; - qdesc->hdwq = idx; - - /* Save the CPU this EQ is affinitised to */ - eqidx = lpfc_find_eq_handle(phba, idx); - qdesc->chann = lpfc_find_cpu_handle(phba, eqidx, - LPFC_FIND_BY_EQ); - phba->sli4_hba.hdwq[idx].hba_eq = qdesc; + qdesc->hdwq = cpup->hdwq; + qdesc->chann = cpu; /* First CPU this EQ is affinitised to */ qdesc->last_cpu = qdesc->chann; + + /* Save the allocated EQ in the Hardware Queue */ + qp->hba_eq = qdesc; + eqi = per_cpu_ptr(phba->sli4_hba.eq_info, qdesc->last_cpu); list_add(&qdesc->cpu_list, &eqi->list); } + /* Now we need to populate the other Hardware Queues, that share + * an IRQ vector, with the associated EQ ptr. + */ + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Check for EQ already allocated in previous loop */ + if (cpup->flag & LPFC_CPU_FIRST_IRQ) + continue; + + /* Check for multiple CPUs per hdwq */ + qp = &phba->sli4_hba.hdwq[cpup->hdwq]; + if (qp->hba_eq) + continue; + + /* We need to share an EQ for this hdwq */ + eqcpu = lpfc_find_cpu_handle(phba, cpup->eq, LPFC_FIND_BY_EQ); + eqcpup = &phba->sli4_hba.cpu_map[eqcpu]; + qp->hba_eq = phba->sli4_hba.hdwq[eqcpup->hdwq].hba_eq; + } /* Allocate SCSI SLI4 CQ/WQs */ for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { @@ -8863,11 +8908,14 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (phba->nvmet_support) { for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { + cpu = lpfc_find_cpu_handle(phba, idx, + LPFC_FIND_BY_HDWQ); qdesc = lpfc_sli4_queue_alloc( phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + phba->sli4_hba.cq_ecount, + cpu); if (!qdesc) { lpfc_printf_log( phba, KERN_ERR, LOG_INIT, @@ -8877,7 +8925,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) } qdesc->qe_valid = 1; qdesc->hdwq = idx; - qdesc->chann = idx; + qdesc->chann = cpu; phba->sli4_hba.nvmet_cqset[idx] = qdesc; } } @@ -8887,10 +8935,11 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) * Create Slow Path Completion Queues (CQs) */ + cpu = lpfc_find_cpu_handle(phba, 0, LPFC_FIND_BY_EQ); /* Create slow-path Mailbox Command Complete Queue */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0500 Failed allocate slow-path mailbox CQ\n"); @@ -8902,7 +8951,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create slow-path ELS Complete Queue */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0501 Failed allocate slow-path ELS CQ\n"); @@ -8921,7 +8970,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.mq_esize, - phba->sli4_hba.mq_ecount); + phba->sli4_hba.mq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0505 Failed allocate slow-path MQ\n"); @@ -8937,7 +8986,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create slow-path ELS Work Queue */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.wq_esize, - phba->sli4_hba.wq_ecount); + phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0504 Failed allocate slow-path ELS WQ\n"); @@ -8951,7 +9000,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create NVME LS Complete Queue */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "6079 Failed allocate NVME LS CQ\n"); @@ -8964,7 +9013,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create NVME LS Work Queue */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.wq_esize, - phba->sli4_hba.wq_ecount); + phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "6080 Failed allocate NVME LS WQ\n"); @@ -8982,7 +9031,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create Receive Queue for header */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.rq_esize, - phba->sli4_hba.rq_ecount); + phba->sli4_hba.rq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0506 Failed allocate receive HRQ\n"); @@ -8993,7 +9042,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create Receive Queue for data */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.rq_esize, - phba->sli4_hba.rq_ecount); + phba->sli4_hba.rq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0507 Failed allocate receive DRQ\n"); @@ -9004,11 +9053,14 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if ((phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) && phba->nvmet_support) { for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { + cpu = lpfc_find_cpu_handle(phba, idx, + LPFC_FIND_BY_HDWQ); /* Create NVMET Receive Queue for header */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.rq_esize, - LPFC_NVMET_RQE_DEF_COUNT); + LPFC_NVMET_RQE_DEF_COUNT, + cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3146 Failed allocate " @@ -9019,8 +9071,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.nvmet_mrq_hdr[idx] = qdesc; /* Only needed for header of RQ pair */ - qdesc->rqbp = kzalloc(sizeof(struct lpfc_rqb), - GFP_KERNEL); + qdesc->rqbp = kzalloc_node(sizeof(*qdesc->rqbp), + GFP_KERNEL, + cpu_to_node(cpu)); if (qdesc->rqbp == NULL) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "6131 Failed allocate " @@ -9035,7 +9088,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.rq_esize, - LPFC_NVMET_RQE_DEF_COUNT); + LPFC_NVMET_RQE_DEF_COUNT, + cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3156 Failed allocate " @@ -9100,23 +9154,31 @@ static inline void lpfc_sli4_release_hdwq(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *hdwq; + struct lpfc_queue *eq; uint32_t idx; hdwq = phba->sli4_hba.hdwq; - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { - if (idx < phba->cfg_irq_chann) - lpfc_sli4_queue_free(hdwq[idx].hba_eq); - hdwq[idx].hba_eq = NULL; + /* Loop thru all Hardware Queues */ + for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { + /* Free the CQ/WQ corresponding to the Hardware Queue */ lpfc_sli4_queue_free(hdwq[idx].fcp_cq); lpfc_sli4_queue_free(hdwq[idx].nvme_cq); lpfc_sli4_queue_free(hdwq[idx].fcp_wq); lpfc_sli4_queue_free(hdwq[idx].nvme_wq); + hdwq[idx].hba_eq = NULL; hdwq[idx].fcp_cq = NULL; hdwq[idx].nvme_cq = NULL; hdwq[idx].fcp_wq = NULL; hdwq[idx].nvme_wq = NULL; } + /* Loop thru all IRQ vectors */ + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + /* Free the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[idx].eq; + lpfc_sli4_queue_free(eq); + phba->sli4_hba.hba_eq_hdl[idx].eq = NULL; + } } /** @@ -9134,6 +9196,20 @@ lpfc_sli4_release_hdwq(struct lpfc_hba *phba) void lpfc_sli4_queue_destroy(struct lpfc_hba *phba) { + /* + * Set FREE_INIT before beginning to free the queues. + * Wait until the users of queues to acknowledge to + * release queues by clearing FREE_WAIT. + */ + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag |= LPFC_QUEUE_FREE_INIT; + while (phba->sli.sli_flag & LPFC_QUEUE_FREE_WAIT) { + spin_unlock_irq(&phba->hbalock); + msleep(20); + spin_lock_irq(&phba->hbalock); + } + spin_unlock_irq(&phba->hbalock); + /* Release HBA eqs */ if (phba->sli4_hba.hdwq) lpfc_sli4_release_hdwq(phba); @@ -9172,6 +9248,11 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) /* Everything on this list has been freed */ INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list); + + /* Done with freeing the queues */ + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag &= ~LPFC_QUEUE_FREE_INIT; + spin_unlock_irq(&phba->hbalock); } int @@ -9231,7 +9312,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, rc = lpfc_wq_create(phba, wq, cq, qtype); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6123 Fail setup fastpath WQ (%d), rc = 0x%x\n", + "4618 Fail setup fastpath WQ (%d), rc = 0x%x\n", qidx, (uint32_t)rc); /* no need to tear down cq - caller will do so */ return rc; @@ -9271,20 +9352,21 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, * This routine will populate the cq_lookup table by all * available CQ queue_id's. **/ -void +static void lpfc_setup_cq_lookup(struct lpfc_hba *phba) { struct lpfc_queue *eq, *childq; - struct lpfc_sli4_hdw_queue *qp; int qidx; - qp = phba->sli4_hba.hdwq; memset(phba->sli4_hba.cq_lookup, 0, (sizeof(struct lpfc_queue *) * (phba->sli4_hba.cq_max + 1))); + /* Loop thru all IRQ vectors */ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { - eq = qp[qidx].hba_eq; + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; if (!eq) continue; + /* Loop through all CQs associated with that EQ */ list_for_each_entry(childq, &eq->child_list, list) { if (childq->queue_id > phba->sli4_hba.cq_max) continue; @@ -9313,9 +9395,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) { uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_vector_map_info *cpup; struct lpfc_sli4_hdw_queue *qp; LPFC_MBOXQ_t *mboxq; - int qidx; + int qidx, cpu; uint32_t length, usdelay; int rc = -ENOMEM; @@ -9376,32 +9459,55 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = -ENOMEM; goto out_error; } + + /* Loop thru all IRQ vectors */ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { - if (!qp[qidx].hba_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0522 Fast-path EQ (%d) not " - "allocated\n", qidx); - rc = -ENOMEM; - goto out_destroy; - } - rc = lpfc_eq_create(phba, qp[qidx].hba_eq, - phba->cfg_fcp_imax); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0523 Failed setup of fast-path EQ " - "(%d), rc = 0x%x\n", qidx, - (uint32_t)rc); - goto out_destroy; + /* Create HBA Event Queues (EQs) in order */ + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Look for the CPU thats using that vector with + * LPFC_CPU_FIRST_IRQ set. + */ + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) + continue; + if (qidx != cpup->eq) + continue; + + /* Create an EQ for that vector */ + rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq, + phba->cfg_fcp_imax); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0523 Failed setup of fast-path" + " EQ (%d), rc = 0x%x\n", + cpup->eq, (uint32_t)rc); + goto out_destroy; + } + + /* Save the EQ for that vector in the hba_eq_hdl */ + phba->sli4_hba.hba_eq_hdl[cpup->eq].eq = + qp[cpup->hdwq].hba_eq; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2584 HBA EQ setup: queue[%d]-id=%d\n", + cpup->eq, + qp[cpup->hdwq].hba_eq->queue_id); } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2584 HBA EQ setup: queue[%d]-id=%d\n", qidx, - qp[qidx].hba_eq->queue_id); } + /* Loop thru all Hardware Queues */ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { + cpu = lpfc_find_cpu_handle(phba, qidx, + LPFC_FIND_BY_HDWQ); + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Create the CQ/WQ corresponding to the + * Hardware Queue + */ rc = lpfc_create_wq_cq(phba, - qp[qidx].hba_eq, + phba->sli4_hba.hdwq[cpup->hdwq].hba_eq, qp[qidx].nvme_cq, qp[qidx].nvme_wq, &phba->sli4_hba.hdwq[qidx].nvme_cq_map, @@ -9417,8 +9523,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) } for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { + cpu = lpfc_find_cpu_handle(phba, qidx, LPFC_FIND_BY_HDWQ); + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Create the CQ/WQ corresponding to the Hardware Queue */ rc = lpfc_create_wq_cq(phba, - qp[qidx].hba_eq, + phba->sli4_hba.hdwq[cpup->hdwq].hba_eq, qp[qidx].fcp_cq, qp[qidx].fcp_wq, &phba->sli4_hba.hdwq[qidx].fcp_cq_map, @@ -9670,6 +9780,7 @@ void lpfc_sli4_queue_unset(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *qp; + struct lpfc_queue *eq; int qidx; /* Unset mailbox command work queue */ @@ -9721,14 +9832,20 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) /* Unset fast-path SLI4 queues */ if (phba->sli4_hba.hdwq) { + /* Loop thru all Hardware Queues */ for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { + /* Destroy the CQ/WQ corresponding to Hardware Queue */ qp = &phba->sli4_hba.hdwq[qidx]; lpfc_wq_destroy(phba, qp->fcp_wq); lpfc_wq_destroy(phba, qp->nvme_wq); lpfc_cq_destroy(phba, qp->fcp_cq); lpfc_cq_destroy(phba, qp->nvme_cq); - if (qidx < phba->cfg_irq_chann) - lpfc_eq_destroy(phba, qp->hba_eq); + } + /* Loop thru all IRQ vectors */ + for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { + /* Destroy the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; + lpfc_eq_destroy(phba, eq); } } @@ -10518,11 +10635,12 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba) } /** - * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified EQ + * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified Queue * @phba: pointer to lpfc hba data structure. * @id: EQ vector index or Hardware Queue index * @match: LPFC_FIND_BY_EQ = match by EQ * LPFC_FIND_BY_HDWQ = match by Hardware Queue + * Return the CPU that matches the selection criteria */ static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match) @@ -10530,40 +10648,27 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match) struct lpfc_vector_map_info *cpup; int cpu; - /* Find the desired phys_id for the specified EQ */ + /* Loop through all CPUs */ for_each_present_cpu(cpu) { cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* If we are matching by EQ, there may be multiple CPUs using + * using the same vector, so select the one with + * LPFC_CPU_FIRST_IRQ set. + */ if ((match == LPFC_FIND_BY_EQ) && + (cpup->flag & LPFC_CPU_FIRST_IRQ) && (cpup->irq != LPFC_VECTOR_MAP_EMPTY) && (cpup->eq == id)) return cpu; + + /* If matching by HDWQ, select the first CPU that matches */ if ((match == LPFC_FIND_BY_HDWQ) && (cpup->hdwq == id)) return cpu; } return 0; } -/** - * lpfc_find_eq_handle - Find the EQ that corresponds to the specified - * Hardware Queue - * @phba: pointer to lpfc hba data structure. - * @hdwq: Hardware Queue index - */ -static uint16_t -lpfc_find_eq_handle(struct lpfc_hba *phba, uint16_t hdwq) -{ - struct lpfc_vector_map_info *cpup; - int cpu; - - /* Find the desired phys_id for the specified EQ */ - for_each_present_cpu(cpu) { - cpup = &phba->sli4_hba.cpu_map[cpu]; - if (cpup->hdwq == hdwq) - return cpup->eq; - } - return 0; -} - #ifdef CONFIG_X86 /** * lpfc_find_hyper - Determine if the CPU map entry is hyper-threaded @@ -10604,24 +10709,31 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu, static void lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) { - int i, cpu, idx; + int i, cpu, idx, new_cpu, start_cpu, first_cpu; int max_phys_id, min_phys_id; int max_core_id, min_core_id; struct lpfc_vector_map_info *cpup; + struct lpfc_vector_map_info *new_cpup; const struct cpumask *maskp; #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif /* Init cpu_map array */ - memset(phba->sli4_hba.cpu_map, 0xff, - (sizeof(struct lpfc_vector_map_info) * - phba->sli4_hba.num_possible_cpu)); + for_each_possible_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + cpup->phys_id = LPFC_VECTOR_MAP_EMPTY; + cpup->core_id = LPFC_VECTOR_MAP_EMPTY; + cpup->hdwq = LPFC_VECTOR_MAP_EMPTY; + cpup->eq = LPFC_VECTOR_MAP_EMPTY; + cpup->irq = LPFC_VECTOR_MAP_EMPTY; + cpup->flag = 0; + } max_phys_id = 0; - min_phys_id = 0xffff; + min_phys_id = LPFC_VECTOR_MAP_EMPTY; max_core_id = 0; - min_core_id = 0xffff; + min_core_id = LPFC_VECTOR_MAP_EMPTY; /* Update CPU map with physical id and core id of each CPU */ for_each_present_cpu(cpu) { @@ -10630,13 +10742,12 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) cpuinfo = &cpu_data(cpu); cpup->phys_id = cpuinfo->phys_proc_id; cpup->core_id = cpuinfo->cpu_core_id; - cpup->hyper = lpfc_find_hyper(phba, cpu, - cpup->phys_id, cpup->core_id); + if (lpfc_find_hyper(phba, cpu, cpup->phys_id, cpup->core_id)) + cpup->flag |= LPFC_CPU_MAP_HYPER; #else /* No distinction between CPUs for other platforms */ cpup->phys_id = 0; cpup->core_id = cpu; - cpup->hyper = 0; #endif lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -10662,23 +10773,216 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) eqi->icnt = 0; } + /* This loop sets up all CPUs that are affinitized with a + * irq vector assigned to the driver. All affinitized CPUs + * will get a link to that vectors IRQ and EQ. + */ for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + /* Get a CPU mask for all CPUs affinitized to this vector */ maskp = pci_irq_get_affinity(phba->pcidev, idx); if (!maskp) continue; + i = 0; + /* Loop through all CPUs associated with vector idx */ for_each_cpu_and(cpu, maskp, cpu_present_mask) { + /* Set the EQ index and IRQ for that vector */ cpup = &phba->sli4_hba.cpu_map[cpu]; cpup->eq = idx; - cpup->hdwq = idx; cpup->irq = pci_irq_vector(phba->pcidev, idx); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3336 Set Affinity: CPU %d " - "hdwq %d irq %d\n", - cpu, cpup->hdwq, cpup->irq); + "irq %d eq %d\n", + cpu, cpup->irq, cpup->eq); + + /* If this is the first CPU thats assigned to this + * vector, set LPFC_CPU_FIRST_IRQ. + */ + if (!i) + cpup->flag |= LPFC_CPU_FIRST_IRQ; + i++; } } + + /* After looking at each irq vector assigned to this pcidev, its + * possible to see that not ALL CPUs have been accounted for. + * Next we will set any unassigned (unaffinitized) cpu map + * entries to a IRQ on the same phys_id. + */ + first_cpu = cpumask_first(cpu_present_mask); + start_cpu = first_cpu; + + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Is this CPU entry unassigned */ + if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) { + /* Mark CPU as IRQ not assigned by the kernel */ + cpup->flag |= LPFC_CPU_MAP_UNASSIGN; + + /* If so, find a new_cpup thats on the the SAME + * phys_id as cpup. start_cpu will start where we + * left off so all unassigned entries don't get assgined + * the IRQ of the first entry. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && + (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) && + (new_cpup->phys_id == cpup->phys_id)) + goto found_same; + new_cpu = cpumask_next( + new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + /* At this point, we leave the CPU as unassigned */ + continue; +found_same: + /* We found a matching phys_id, so copy the IRQ info */ + cpup->eq = new_cpup->eq; + cpup->irq = new_cpup->irq; + + /* Bump start_cpu to the next slot to minmize the + * chance of having multiple unassigned CPU entries + * selecting the same IRQ. + */ + start_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (start_cpu == nr_cpumask_bits) + start_cpu = first_cpu; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3337 Set Affinity: CPU %d " + "irq %d from id %d same " + "phys_id (%d)\n", + cpu, cpup->irq, new_cpu, cpup->phys_id); + } + } + + /* Set any unassigned cpu map entries to a IRQ on any phys_id */ + start_cpu = first_cpu; + + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Is this entry unassigned */ + if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) { + /* Mark it as IRQ not assigned by the kernel */ + cpup->flag |= LPFC_CPU_MAP_UNASSIGN; + + /* If so, find a new_cpup thats on ANY phys_id + * as the cpup. start_cpu will start where we + * left off so all unassigned entries don't get + * assigned the IRQ of the first entry. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && + (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY)) + goto found_any; + new_cpu = cpumask_next( + new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + /* We should never leave an entry unassigned */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3339 Set Affinity: CPU %d " + "irq %d UNASSIGNED\n", + cpup->hdwq, cpup->irq); + continue; +found_any: + /* We found an available entry, copy the IRQ info */ + cpup->eq = new_cpup->eq; + cpup->irq = new_cpup->irq; + + /* Bump start_cpu to the next slot to minmize the + * chance of having multiple unassigned CPU entries + * selecting the same IRQ. + */ + start_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (start_cpu == nr_cpumask_bits) + start_cpu = first_cpu; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3338 Set Affinity: CPU %d " + "irq %d from id %d (%d/%d)\n", + cpu, cpup->irq, new_cpu, + new_cpup->phys_id, new_cpup->core_id); + } + } + + /* Finally we need to associate a hdwq with each cpu_map entry + * This will be 1 to 1 - hdwq to cpu, unless there are less + * hardware queues then CPUs. For that case we will just round-robin + * the available hardware queues as they get assigned to CPUs. + */ + idx = 0; + start_cpu = 0; + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + if (idx >= phba->cfg_hdw_queue) { + /* We need to reuse a Hardware Queue for another CPU, + * so be smart about it and pick one that has its + * IRQ/EQ mapped to the same phys_id (CPU package). + * and core_id. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) && + (new_cpup->phys_id == cpup->phys_id) && + (new_cpup->core_id == cpup->core_id)) + goto found_hdwq; + new_cpu = cpumask_next( + new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + + /* If we can't match both phys_id and core_id, + * settle for just a phys_id match. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) && + (new_cpup->phys_id == cpup->phys_id)) + goto found_hdwq; + new_cpu = cpumask_next( + new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + + /* Otherwise just round robin on cfg_hdw_queue */ + cpup->hdwq = idx % phba->cfg_hdw_queue; + goto logit; +found_hdwq: + /* We found an available entry, copy the IRQ info */ + start_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (start_cpu == nr_cpumask_bits) + start_cpu = first_cpu; + cpup->hdwq = new_cpup->hdwq; + } else { + /* 1 to 1, CPU to hdwq */ + cpup->hdwq = idx; + } +logit: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3335 Set Affinity: CPU %d (phys %d core %d): " + "hdwq %d eq %d irq %d flg x%x\n", + cpu, cpup->phys_id, cpup->core_id, + cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); + idx++; + } + + /* The cpu_map array will be used later during initialization + * when EQ / CQ / WQs are allocated and configured. + */ return; } @@ -10740,7 +11044,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) phba->cfg_irq_chann, vectors); if (phba->cfg_irq_chann > vectors) phba->cfg_irq_chann = vectors; - if (phba->cfg_nvmet_mrq > vectors) + if (phba->nvmet_support && (phba->cfg_nvmet_mrq > vectors)) phba->cfg_nvmet_mrq = vectors; } @@ -11290,24 +11594,43 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) mbx_sli4_parameters); phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters); phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters); - phba->nvme_support = (bf_get(cfg_nvme, mbx_sli4_parameters) && - bf_get(cfg_xib, mbx_sli4_parameters)); - - if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) || - !phba->nvme_support) { - phba->nvme_support = 0; - phba->nvmet_support = 0; - phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_OFF; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME, - "6101 Disabling NVME support: " - "Not supported by firmware: %d %d\n", - bf_get(cfg_nvme, mbx_sli4_parameters), - bf_get(cfg_xib, mbx_sli4_parameters)); - - /* If firmware doesn't support NVME, just use SCSI support */ - if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) - return -ENODEV; - phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; + + /* Check for firmware nvme support */ + rc = (bf_get(cfg_nvme, mbx_sli4_parameters) && + bf_get(cfg_xib, mbx_sli4_parameters)); + + if (rc) { + /* Save this to indicate the Firmware supports NVME */ + sli4_params->nvme = 1; + + /* Firmware NVME support, check driver FC4 NVME support */ + if (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME, + "6133 Disabling NVME support: " + "FC4 type not supported: x%x\n", + phba->cfg_enable_fc4_type); + goto fcponly; + } + } else { + /* No firmware NVME support, check driver FC4 NVME support */ + sli4_params->nvme = 0; + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME, + "6101 Disabling NVME support: Not " + "supported by firmware (%d %d) x%x\n", + bf_get(cfg_nvme, mbx_sli4_parameters), + bf_get(cfg_xib, mbx_sli4_parameters), + phba->cfg_enable_fc4_type); +fcponly: + phba->nvme_support = 0; + phba->nvmet_support = 0; + phba->cfg_nvmet_mrq = 0; + + /* If no FC4 type support, move to just SCSI support */ + if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) + return -ENODEV; + phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; + } } /* Only embed PBDE for if_type 6, PBDE support requires xib be set */ @@ -13046,7 +13369,7 @@ lpfc_io_resume(struct pci_dev *pdev) * is destroyed. * **/ -void +static void lpfc_sli4_oas_verify(struct lpfc_hba *phba) { diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 6172682a24ba..59252bfca14e 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -360,6 +360,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, case NLP_STE_NPR_NODE: if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) break; + /* fall through */ case NLP_STE_REG_LOGIN_ISSUE: case NLP_STE_PRLI_ISSUE: case NLP_STE_UNMAPPED_NODE: @@ -870,7 +871,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * This function will send a unreg_login mailbox command to the firmware * to release a rpi. **/ -void +static void lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint16_t rpi) { @@ -1732,7 +1733,6 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; MAILBOX_t *mb = &pmb->u.mb; uint32_t did = mb->un.varWords[1]; - int rc = 0; if (mb->mbxStatus) { /* RegLogin failed */ @@ -1805,8 +1805,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, * GFT_ID to determine if remote port supports NVME. */ if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) { - rc = lpfc_ns_cmd(vport, SLI_CTNS_GFT_ID, - 0, ndlp->nlp_DID); + lpfc_ns_cmd(vport, SLI_CTNS_GFT_ID, 0, + ndlp->nlp_DID); return ndlp->nlp_state; } ndlp->nlp_fc4_type = NLP_FC4_FCP; diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 1aa00d2c3f74..946642cee3df 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -229,7 +229,7 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, if (qhandle == NULL) return -ENOMEM; - qhandle->cpu_id = smp_processor_id(); + qhandle->cpu_id = raw_smp_processor_id(); qhandle->qidx = qidx; /* * NVME qidx == 0 is the admin queue, so both admin queue @@ -312,7 +312,7 @@ lpfc_nvme_localport_delete(struct nvme_fc_local_port *localport) * Return value : * None */ -void +static void lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) { struct lpfc_nvme_rport *rport = remoteport->private; @@ -1106,13 +1106,16 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, lpfc_ncmd, nCmd, lpfc_ncmd->cur_iocbq.sli4_xritag, bf_get(lpfc_wcqe_c_xb, wcqe)); + /* fall through */ default: out_err: lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6072 NVME Completion Error: xri %x " - "status x%x result x%x placed x%x\n", + "status x%x result x%x [x%x] " + "placed x%x\n", lpfc_ncmd->cur_iocbq.sli4_xritag, lpfc_ncmd->status, lpfc_ncmd->result, + wcqe->parameter, wcqe->total_data_placed); nCmd->transferred_length = 0; nCmd->rcv_rsplen = 0; @@ -1140,7 +1143,7 @@ out_err: if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) { uint32_t cpu; idx = lpfc_ncmd->cur_iocbq.hba_wqidx; - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); if (cpu < LPFC_CHECK_CPU_CNT) { if (lpfc_ncmd->cpu != cpu) lpfc_printf_vlog(vport, @@ -1558,7 +1561,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) { idx = lpfc_queue_info->index; } else { - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); idx = phba->sli4_hba.cpu_map[cpu].hdwq; } @@ -1638,7 +1641,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, lpfc_ncmd->ts_cmd_wqput = ktime_get_ns(); if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) { - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); if (cpu < LPFC_CHECK_CPU_CNT) { lpfc_ncmd->cpu = cpu; if (idx != cpu) @@ -2080,15 +2083,15 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) lpfc_nvme_template.max_hw_queues = phba->sli4_hba.num_present_cpu; + if (!IS_ENABLED(CONFIG_NVME_FC)) + return ret; + /* localport is allocated from the stack, but the registration * call allocates heap memory as well as the private area. */ -#if (IS_ENABLED(CONFIG_NVME_FC)) + ret = nvme_fc_register_localport(&nfcp_info, &lpfc_nvme_template, &vport->phba->pcidev->dev, &localport); -#else - ret = -ENOMEM; -#endif if (!ret) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME | LOG_NVME_DISC, "6005 Successfully registered local " @@ -2123,6 +2126,7 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) return ret; } +#if (IS_ENABLED(CONFIG_NVME_FC)) /* lpfc_nvme_lport_unreg_wait - Wait for the host to complete an lport unreg. * * The driver has to wait for the host nvme transport to callback @@ -2133,14 +2137,15 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) * An uninterruptible wait is used because of the risk of transport-to- * driver state mismatch. */ -void +static void lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, struct lpfc_nvme_lport *lport, struct completion *lport_unreg_cmp) { -#if (IS_ENABLED(CONFIG_NVME_FC)) u32 wait_tmo; - int ret; + int ret, i, pending = 0; + struct lpfc_sli_ring *pring; + struct lpfc_hba *phba = vport->phba; /* Host transport has to clean up and confirm requiring an indefinite * wait. Print a message if a 10 second wait expires and renew the @@ -2150,10 +2155,18 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, while (true) { ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo); if (unlikely(!ret)) { + pending = 0; + for (i = 0; i < phba->cfg_hdw_queue; i++) { + pring = phba->sli4_hba.hdwq[i].nvme_wq->pring; + if (!pring) + continue; + if (pring->txcmplq_cnt) + pending += pring->txcmplq_cnt; + } lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, "6176 Lport %p Localport %p wait " - "timed out. Renewing.\n", - lport, vport->localport); + "timed out. Pending %d. Renewing.\n", + lport, vport->localport, pending); continue; } break; @@ -2161,8 +2174,8 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6177 Lport %p Localport %p Complete Success\n", lport, vport->localport); -#endif } +#endif /** * lpfc_nvme_destroy_localport - Destroy lpfc_nvme bound to nvme transport. @@ -2399,6 +2412,50 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) #endif } +/** + * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport + * + * If the ndlp represents an NVME Target, that we are logged into, + * ping the NVME FC Transport layer to initiate a device rescan + * on this remote NPort. + */ +void +lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_nvme_rport *rport; + struct nvme_fc_remote_port *remoteport; + + rport = ndlp->nrport; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, + "6170 Rescan NPort DID x%06x type x%x " + "state x%x rport %p\n", + ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_state, rport); + if (!rport) + goto input_err; + remoteport = rport->remoteport; + if (!remoteport) + goto input_err; + + /* Only rescan if we are an NVME target in the MAPPED state */ + if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY && + ndlp->nlp_state == NLP_STE_MAPPED_NODE) { + nvme_fc_rescan_remoteport(remoteport); + + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + "6172 NVME rescanned DID x%06x " + "port_state x%x\n", + ndlp->nlp_DID, remoteport->port_state); + } + return; +input_err: + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + "6169 State error: lport %p, rport%p FCID x%06x\n", + vport->localport, ndlp->rport, ndlp->nlp_DID); +#endif +} + /* lpfc_nvme_unregister_port - unbind the DID and port_role from this rport. * * There is no notion of Devloss or rport recovery from the current diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 361e2b103648..faa596f9e861 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -220,19 +220,68 @@ lpfc_nvmet_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } -void +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +static struct lpfc_nvmet_rcv_ctx * +lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) +{ + struct lpfc_nvmet_rcv_ctx *ctxp; + unsigned long iflag; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) { + if (ctxp->ctxbuf->sglq->sli4_xritag != xri) + continue; + + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); + if (found) + return ctxp; + + return NULL; +} + +static struct lpfc_nvmet_rcv_ctx * +lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) +{ + struct lpfc_nvmet_rcv_ctx *ctxp; + unsigned long iflag; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) { + if (ctxp->oxid != oxid || ctxp->sid != sid) + continue; + + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); + if (found) + return ctxp; + + return NULL; +} +#endif + +static void lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) { lockdep_assert_held(&ctxp->ctxlock); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6313 NVMET Defer ctx release xri x%x flg x%x\n", + "6313 NVMET Defer ctx release oxid x%x flg x%x\n", ctxp->oxid, ctxp->flag); if (ctxp->flag & LPFC_NVMET_CTX_RLS) return; ctxp->flag |= LPFC_NVMET_CTX_RLS; + spin_lock(&phba->sli4_hba.t_active_list_lock); + list_del(&ctxp->list); + spin_unlock(&phba->sli4_hba.t_active_list_lock); spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_add_tail(&ctxp->list, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); @@ -325,7 +374,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) struct fc_frame_header *fc_hdr; struct rqb_dmabuf *nvmebuf; struct lpfc_nvmet_ctx_info *infop; - uint32_t *payload; uint32_t size, oxid, sid; int cpu; unsigned long iflag; @@ -344,16 +392,23 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) } if (ctxp->rqb_buffer) { - nvmebuf = ctxp->rqb_buffer; spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->rqb_buffer = NULL; - if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { - ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ; - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); + nvmebuf = ctxp->rqb_buffer; + /* check if freed in another path whilst acquiring lock */ + if (nvmebuf) { + ctxp->rqb_buffer = NULL; + if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { + ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, + nvmebuf); + } else { + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + /* repost */ + lpfc_rq_buf_free(phba, &nvmebuf->hbuf); + } } else { spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ } } ctxp->state = LPFC_NVMET_STE_FREE; @@ -370,7 +425,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); oxid = be16_to_cpu(fc_hdr->fh_ox_id); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - payload = (uint32_t *)(nvmebuf->dbuf.virt); size = nvmebuf->bytes_recv; sid = sli4_sid_from_fc_hdr(fc_hdr); @@ -390,8 +444,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) spin_lock_init(&ctxp->ctxlock); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (ctxp->ts_cmd_nvme) { - ctxp->ts_cmd_nvme = ktime_get_ns(); + /* NOTE: isr time stamp is stale when context is re-assigned*/ + if (ctxp->ts_isr_cmd) { + ctxp->ts_cmd_nvme = 0; ctxp->ts_nvme_data = 0; ctxp->ts_data_wqput = 0; ctxp->ts_isr_data = 0; @@ -404,9 +459,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) #endif atomic_inc(&tgtp->rcv_fcp_cmd_in); - /* flag new work queued, replacement buffer has already - * been reposted - */ + /* Indicate that a replacement buffer has been posted */ spin_lock_irqsave(&ctxp->ctxlock, iflag); ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ; spin_unlock_irqrestore(&ctxp->ctxlock, iflag); @@ -435,7 +488,10 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) * Use the CPU context list, from the MRQ the IO was received on * (ctxp->idx), to save context structure. */ - cpu = smp_processor_id(); + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_del_init(&ctxp->list); + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); + cpu = raw_smp_processor_id(); infop = lpfc_get_ctx_list(phba, cpu, ctxp->idx); spin_lock_irqsave(&infop->nvmet_ctx_list_lock, iflag); list_add_tail(&ctx_buf->list, &infop->nvmet_ctx_list); @@ -702,8 +758,10 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, } lpfc_printf_log(phba, KERN_INFO, logerr, - "6315 IO Error Cmpl xri x%x: %x/%x XBUSY:x%x\n", - ctxp->oxid, status, result, ctxp->flag); + "6315 IO Error Cmpl oxid: x%x xri: x%x %x/%x " + "XBUSY:x%x\n", + ctxp->oxid, ctxp->ctxbuf->sglq->sli4_xritag, + status, result, ctxp->flag); } else { rsp->fcp_error = NVME_SC_SUCCESS; @@ -765,7 +823,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) { - id = smp_processor_id(); + id = raw_smp_processor_id(); if (id < LPFC_CHECK_CPU_CNT) { if (ctxp->cpu != id) lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, @@ -851,7 +909,6 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, * before freeing ctxp and iocbq. */ lpfc_in_buf_free(phba, &nvmebuf->dbuf); - ctxp->rqb_buffer = 0; atomic_inc(&nvmep->xmt_ls_rsp); return 0; } @@ -906,7 +963,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, ctxp->hdwq = &phba->sli4_hba.hdwq[rsp->hwqid]; if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) { - int id = smp_processor_id(); + int id = raw_smp_processor_id(); if (id < LPFC_CHECK_CPU_CNT) { if (rsp->hwqid != id) lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, @@ -924,7 +981,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, (ctxp->state == LPFC_NVMET_STE_ABORT)) { atomic_inc(&lpfc_nvmep->xmt_fcp_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6102 IO xri x%x aborted\n", + "6102 IO oxid x%x aborted\n", ctxp->oxid); rc = -ENXIO; goto aerr; @@ -1024,7 +1081,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, ctxp->hdwq = &phba->sli4_hba.hdwq[0]; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n", + "6103 NVMET Abort op: oxid x%x flg x%x ste %d\n", ctxp->oxid, ctxp->flag, ctxp->state); lpfc_nvmeio_data(phba, "NVMET FCP ABRT: xri x%x flg x%x ste x%x\n", @@ -1037,7 +1094,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, /* Since iaab/iaar are NOT set, we need to check * if the firmware is in process of aborting IO */ - if (ctxp->flag & LPFC_NVMET_XBUSY) { + if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) { spin_unlock_irqrestore(&ctxp->ctxlock, flags); return; } @@ -1100,6 +1157,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, ctxp->state, aborting); atomic_inc(&lpfc_nvmep->xmt_fcp_release); + ctxp->flag &= ~LPFC_NVMET_TNOTIFY; if (aborting) return; @@ -1120,11 +1178,11 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, lpfc_nvmeio_data(phba, "NVMET DEFERRCV: xri x%x sz %d CPU %02x\n", - ctxp->oxid, ctxp->size, smp_processor_id()); + ctxp->oxid, ctxp->size, raw_smp_processor_id()); if (!nvmebuf) { lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6425 Defer rcv: no buffer xri x%x: " + "6425 Defer rcv: no buffer oxid x%x: " "flg %x ste %x\n", ctxp->oxid, ctxp->flag, ctxp->state); return; @@ -1141,6 +1199,22 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } +static void +lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) +{ + struct lpfc_nvmet_tgtport *tgtp; + struct lpfc_hba *phba; + uint32_t rc; + + tgtp = tgtport->private; + phba = tgtp->phba; + + rc = lpfc_issue_els_rscn(phba->pport, 0); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + "6420 NVMET subsystem change: Notification %s\n", + (rc) ? "Failed" : "Sent"); +} + static struct nvmet_fc_target_template lpfc_tgttemplate = { .targetport_delete = lpfc_nvmet_targetport_delete, .xmt_ls_rsp = lpfc_nvmet_xmt_ls_rsp, @@ -1148,6 +1222,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { .fcp_abort = lpfc_nvmet_xmt_fcp_abort, .fcp_req_release = lpfc_nvmet_xmt_fcp_release, .defer_rcv = lpfc_nvmet_defer_rcv, + .discovery_event = lpfc_nvmet_discovery_event, .max_hw_queues = 1, .max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS, @@ -1499,10 +1574,12 @@ void lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri) { +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; struct lpfc_nvmet_tgtport *tgtp; + struct nvmefc_tgt_fcp_req *req = NULL; struct lpfc_nodelist *ndlp; unsigned long iflag = 0; int rrq_empty = 0; @@ -1533,7 +1610,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, */ if (ctxp->flag & LPFC_NVMET_CTX_RLS && !(ctxp->flag & LPFC_NVMET_ABORT_OP)) { - list_del(&ctxp->list); + list_del_init(&ctxp->list); released = true; } ctxp->flag &= ~LPFC_NVMET_XBUSY; @@ -1553,7 +1630,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, } lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6318 XB aborted oxid %x flg x%x (%x)\n", + "6318 XB aborted oxid x%x flg x%x (%x)\n", ctxp->oxid, ctxp->flag, released); if (released) lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); @@ -1564,6 +1641,33 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, } spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); + + ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri); + if (ctxp) { + /* + * Abort already done by FW, so BA_ACC sent. + * However, the transport may be unaware. + */ + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6323 NVMET Rcv ABTS xri x%x ctxp state x%x " + "flag x%x oxid x%x rxid x%x\n", + xri, ctxp->state, ctxp->flag, ctxp->oxid, + rxid); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= LPFC_NVMET_ABTS_RCV; + ctxp->state = LPFC_NVMET_STE_ABORT; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + req = &ctxp->ctx.fcp_req; + if (req) + nvmet_fc_rcv_fcp_abort(phba->targetport, req); + } +#endif } int @@ -1574,19 +1678,23 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; struct nvmefc_tgt_fcp_req *rsp; - uint16_t xri; + uint32_t sid; + uint16_t oxid, xri; unsigned long iflag = 0; - xri = be16_to_cpu(fc_hdr->fh_ox_id); + sid = sli4_sid_from_fc_hdr(fc_hdr); + oxid = be16_to_cpu(fc_hdr->fh_ox_id); spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_for_each_entry_safe(ctxp, next_ctxp, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, list) { - if (ctxp->ctxbuf->sglq->sli4_xritag != xri) + if (ctxp->oxid != oxid || ctxp->sid != sid) continue; + xri = ctxp->ctxbuf->sglq->sli4_xritag; + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -1596,7 +1704,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", - xri, smp_processor_id(), 0); + xri, raw_smp_processor_id(), 0); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6319 NVMET Rcv ABTS:acc xri x%x\n", xri); @@ -1611,11 +1719,93 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", - xri, smp_processor_id(), 1); + /* check the wait list */ + if (phba->sli4_hba.nvmet_io_wait_cnt) { + struct rqb_dmabuf *nvmebuf; + struct fc_frame_header *fc_hdr_tmp; + u32 sid_tmp; + u16 oxid_tmp; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); + + /* match by oxid and s_id */ + list_for_each_entry(nvmebuf, + &phba->sli4_hba.lpfc_nvmet_io_wait_list, + hbuf.list) { + fc_hdr_tmp = (struct fc_frame_header *) + (nvmebuf->hbuf.virt); + oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id); + sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp); + if (oxid_tmp != oxid || sid_tmp != sid) + continue; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6321 NVMET Rcv ABTS oxid x%x from x%x " + "is waiting for a ctxp\n", + oxid, sid); + + list_del_init(&nvmebuf->hbuf.list); + phba->sli4_hba.nvmet_io_wait_cnt--; + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock, + iflag); + + /* free buffer since already posted a new DMA buffer to RQ */ + if (found) { + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); + /* Respond with BA_ACC accordingly */ + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + } + + /* check active list */ + ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid); + if (ctxp) { + xri = ctxp->ctxbuf->sglq->sli4_xritag; + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x " + "flag x%x state x%x\n", + ctxp->oxid, xri, ctxp->flag, ctxp->state); + + if (ctxp->flag & LPFC_NVMET_TNOTIFY) { + /* Notify the transport */ + nvmet_fc_rcv_fcp_abort(phba->targetport, + &ctxp->ctx.fcp_req); + } else { + cancel_work_sync(&ctxp->ctxbuf->defer_work); + spin_lock_irqsave(&ctxp->ctxlock, iflag); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + } + if (ctxp->state == LPFC_NVMET_STE_RCV) + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + else + lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + + lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n", + oxid, raw_smp_processor_id(), 1); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6320 NVMET Rcv ABTS:rjt xri x%x\n", xri); + "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid); /* Respond with BA_RJT accordingly */ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0); @@ -1699,6 +1889,18 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, spin_unlock_irqrestore(&pring->ring_lock, iflags); return; } + if (rc == WQE_SUCCESS) { +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_cmd_nvme) { + if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP) + ctxp->ts_status_wqput = ktime_get_ns(); + else + ctxp->ts_data_wqput = ktime_get_ns(); + } +#endif + } else { + WARN_ON(rc); + } } wq->q_flag &= ~HBA_NVMET_WQFULL; spin_unlock_irqrestore(&pring->ring_lock, iflags); @@ -1725,7 +1927,11 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) } tgtp->tport_unreg_cmp = &tport_unreg_cmp; nvmet_fc_unregister_targetport(phba->targetport); - wait_for_completion_timeout(&tport_unreg_cmp, 5); + if (!wait_for_completion_timeout(tgtp->tport_unreg_cmp, + msecs_to_jiffies(LPFC_NVMET_WAIT_TMO))) + lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + "6179 Unreg targetport %p timeout " + "reached.\n", phba->targetport); lpfc_nvmet_cleanup_io_context(phba); } phba->targetport = NULL; @@ -1843,7 +2049,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) struct lpfc_hba *phba = ctxp->phba; struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; struct lpfc_nvmet_tgtport *tgtp; - uint32_t *payload; + uint32_t *payload, qno; uint32_t rc; unsigned long iflags; @@ -1860,8 +2066,20 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) return; } + if (ctxp->flag & LPFC_NVMET_ABTS_RCV) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6324 IO oxid x%x aborted\n", + ctxp->oxid); + return; + } + payload = (uint32_t *)(nvmebuf->dbuf.virt); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + ctxp->flag |= LPFC_NVMET_TNOTIFY; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_isr_cmd) + ctxp->ts_cmd_nvme = ktime_get_ns(); +#endif /* * The calling sequence should be: * nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done @@ -1876,6 +2094,15 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) /* Process FCP command */ if (rc == 0) { atomic_inc(&tgtp->rcv_fcp_cmd_out); + spin_lock_irqsave(&ctxp->ctxlock, iflags); + if ((ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) || + (nvmebuf != ctxp->rqb_buffer)) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + return; + } + ctxp->rqb_buffer = NULL; + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ return; } @@ -1886,8 +2113,23 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) ctxp->oxid, ctxp->size, ctxp->sid); atomic_inc(&tgtp->rcv_fcp_cmd_out); atomic_inc(&tgtp->defer_fod); + spin_lock_irqsave(&ctxp->ctxlock, iflags); + if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + return; + } + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + /* + * Post a replacement 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); return; } + ctxp->flag &= ~LPFC_NVMET_TNOTIFY; atomic_inc(&tgtp->rcv_fcp_cmd_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", @@ -1977,6 +2219,8 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba, * @phba: pointer to lpfc hba data structure. * @idx: relative index of MRQ vector * @nvmebuf: pointer to lpfc nvme command HBQ data structure. + * @isr_timestamp: in jiffies. + * @cqflag: cq processing information regarding workload. * * This routine is used for processing the WQE associated with a unsolicited * event. It first determines whether there is an existing ndlp that matches @@ -1989,14 +2233,14 @@ static void lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, - uint64_t isr_timestamp) + uint64_t isr_timestamp, + uint8_t cqflag) { struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; struct fc_frame_header *fc_hdr; struct lpfc_nvmet_ctxbuf *ctx_buf; struct lpfc_nvmet_ctx_info *current_infop; - uint32_t *payload; uint32_t size, oxid, sid, qno; unsigned long iflag; int current_cpu; @@ -2020,7 +2264,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, * be empty, thus it would need to be replenished with the * context list from another CPU for this MRQ. */ - current_cpu = smp_processor_id(); + current_cpu = raw_smp_processor_id(); current_infop = lpfc_get_ctx_list(phba, current_cpu, idx); spin_lock_irqsave(¤t_infop->nvmet_ctx_list_lock, iflag); if (current_infop->nvmet_ctx_list_cnt) { @@ -2050,7 +2294,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, #endif lpfc_nvmeio_data(phba, "NVMET FCP RCV: xri x%x sz %d CPU %02x\n", - oxid, size, smp_processor_id()); + oxid, size, raw_smp_processor_id()); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; @@ -2074,10 +2318,12 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, return; } - payload = (uint32_t *)(nvmebuf->dbuf.virt); sid = sli4_sid_from_fc_hdr(fc_hdr); ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list); + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); if (ctxp->state != LPFC_NVMET_STE_FREE) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "6414 NVMET Context corrupt %d %d oxid x%x\n", @@ -2100,24 +2346,41 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, spin_lock_init(&ctxp->ctxlock); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (isr_timestamp) { + if (isr_timestamp) ctxp->ts_isr_cmd = isr_timestamp; - ctxp->ts_cmd_nvme = ktime_get_ns(); - ctxp->ts_nvme_data = 0; - ctxp->ts_data_wqput = 0; - ctxp->ts_isr_data = 0; - ctxp->ts_data_nvme = 0; - ctxp->ts_nvme_status = 0; - ctxp->ts_status_wqput = 0; - ctxp->ts_isr_status = 0; - ctxp->ts_status_nvme = 0; - } else { - ctxp->ts_cmd_nvme = 0; - } + ctxp->ts_cmd_nvme = 0; + ctxp->ts_nvme_data = 0; + ctxp->ts_data_wqput = 0; + ctxp->ts_isr_data = 0; + ctxp->ts_data_nvme = 0; + ctxp->ts_nvme_status = 0; + ctxp->ts_status_wqput = 0; + ctxp->ts_isr_status = 0; + ctxp->ts_status_nvme = 0; #endif atomic_inc(&tgtp->rcv_fcp_cmd_in); - lpfc_nvmet_process_rcv_fcp_req(ctx_buf); + /* check for cq processing load */ + if (!cqflag) { + lpfc_nvmet_process_rcv_fcp_req(ctx_buf); + return; + } + + if (!queue_work(phba->wq, &ctx_buf->defer_work)) { + atomic_inc(&tgtp->rcv_fcp_cmd_drop); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + "6325 Unable to queue work for oxid x%x. " + "FCP Drop IO [x%x x%x x%x]\n", + ctxp->oxid, + atomic_read(&tgtp->rcv_fcp_cmd_in), + atomic_read(&tgtp->rcv_fcp_cmd_out), + atomic_read(&tgtp->xmt_fcp_release)); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, sid, oxid); + } } /** @@ -2154,6 +2417,8 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * @phba: pointer to lpfc hba data structure. * @idx: relative index of MRQ vector * @nvmebuf: pointer to received nvme data structure. + * @isr_timestamp: in jiffies. + * @cqflag: cq processing information regarding workload. * * This routine is used to process an unsolicited event received from a SLI * (Service Level Interface) ring. The actual processing of the data buffer @@ -2165,14 +2430,14 @@ void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, - uint64_t isr_timestamp) + uint64_t isr_timestamp, + uint8_t cqflag) { if (phba->nvmet_support == 0) { lpfc_rq_buf_free(phba, &nvmebuf->hbuf); return; } - lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, - isr_timestamp); + lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, isr_timestamp, cqflag); } /** @@ -2639,8 +2904,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT; nvmewqe->context1 = ndlp; - for (i = 0; i < rsp->sg_cnt; i++) { - sgel = &rsp->sg[i]; + for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) { physaddr = sg_dma_address(sgel); cnt = sg_dma_len(sgel); sgl->addr_hi = putPaddrHigh(physaddr); @@ -2690,12 +2954,11 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, { struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; - uint32_t status, result; + uint32_t result; unsigned long flags; bool released = false; ctxp = cmdwqe->context2; - status = bf_get(lpfc_wcqe_c_status, wcqe); result = wcqe->parameter; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; @@ -2711,7 +2974,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && !(ctxp->flag & LPFC_NVMET_XBUSY)) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_del(&ctxp->list); + list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } @@ -2720,7 +2983,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, atomic_inc(&tgtp->xmt_abort_rsp); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6165 ABORT cmpl: xri x%x flg x%x (%d) " + "6165 ABORT cmpl: oxid x%x flg x%x (%d) " "WCQE: %08x %08x %08x %08x\n", ctxp->oxid, ctxp->flag, released, wcqe->word0, wcqe->total_data_placed, @@ -2761,11 +3024,10 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; unsigned long flags; - uint32_t status, result; + uint32_t result; bool released = false; ctxp = cmdwqe->context2; - status = bf_get(lpfc_wcqe_c_status, wcqe); result = wcqe->parameter; if (!ctxp) { @@ -2796,7 +3058,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && !(ctxp->flag & LPFC_NVMET_XBUSY)) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_del(&ctxp->list); + list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } @@ -2805,7 +3067,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, atomic_inc(&tgtp->xmt_abort_rsp); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6316 ABTS cmpl xri x%x flg x%x (%x) " + "6316 ABTS cmpl oxid x%x flg x%x (%x) " "WCQE: %08x %08x %08x %08x\n", ctxp->oxid, ctxp->flag, released, wcqe->word0, wcqe->total_data_placed, @@ -2842,10 +3104,9 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, { struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; - uint32_t status, result; + uint32_t result; ctxp = cmdwqe->context2; - status = bf_get(lpfc_wcqe_c_status, wcqe); result = wcqe->parameter; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; @@ -3177,7 +3438,7 @@ aerr: spin_lock_irqsave(&ctxp->ctxlock, flags); if (ctxp->flag & LPFC_NVMET_CTX_RLS) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_del(&ctxp->list); + list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } @@ -3186,8 +3447,9 @@ aerr: atomic_inc(&tgtp->xmt_abort_rsp_error); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, - "6135 Failed to Issue ABTS for oxid x%x. Status x%x\n", - ctxp->oxid, rc); + "6135 Failed to Issue ABTS for oxid x%x. Status x%x " + "(%x)\n", + ctxp->oxid, rc, released); if (released) lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); return 1; @@ -3200,7 +3462,6 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; - union lpfc_wqe128 *wqe_abts; unsigned long flags; int rc; @@ -3230,7 +3491,6 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, } } abts_wqeq = ctxp->wqeq; - wqe_abts = &abts_wqeq->wqe; if (lpfc_nvmet_unsol_issue_abort(phba, ctxp, sid, xri) == 0) { rc = WQE_BUSY; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 368deea2bcf8..8ff67deac10a 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -27,10 +27,11 @@ #define LPFC_NVMET_RQE_DEF_COUNT 2048 #define LPFC_NVMET_SUCCESS_LEN 12 -#define LPFC_NVMET_MRQ_OFF 0xffff #define LPFC_NVMET_MRQ_AUTO 0 #define LPFC_NVMET_MRQ_MAX 16 +#define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC) + /* Used for NVME Target */ struct lpfc_nvmet_tgtport { struct lpfc_hba *phba; @@ -139,6 +140,7 @@ struct lpfc_nvmet_rcv_ctx { #define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ #define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ #define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ +#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */ struct rqb_dmabuf *rqb_buffer; struct lpfc_nvmet_ctxbuf *ctxbuf; struct lpfc_sli4_hdw_queue *hdwq; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a497b2c0cb79..f9df800e7067 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -688,7 +688,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t sgl_size, cpu, idx; int tag; - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); if (cmnd && phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) { tag = blk_mq_unique_tag(cmnd->request); idx = blk_mq_unique_tag_to_hwq(tag); @@ -1137,7 +1137,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, break; } - /* Drop thru */ + /* fall through */ case SCSI_PROT_WRITE_INSERT: /* * For WRITE_INSERT, force the error @@ -1256,7 +1256,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc = BG_ERR_TGT | BG_ERR_CHECK; break; } - /* Drop thru */ + /* fall through */ case SCSI_PROT_WRITE_INSERT: /* * For WRITE_INSERT, force the @@ -1338,7 +1338,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, switch (op) { case SCSI_PROT_WRITE_PASS: rc = BG_ERR_CHECK; - /* Drop thru */ + /* fall through */ case SCSI_PROT_WRITE_INSERT: /* @@ -3669,8 +3669,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) { - cpu = smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) + cpu = raw_smp_processor_id(); + if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq) phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++; } #endif @@ -3822,7 +3822,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->cur_iocbq.sli4_lxritag, 0, 0); } - /* else: fall through */ + /* fall through */ default: cmd->result = DID_ERROR << 16; break; @@ -3879,10 +3879,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, */ spin_lock(&lpfc_cmd->buf_lock); lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED; - if (lpfc_cmd->waitq) { + if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); - lpfc_cmd->waitq = NULL; - } spin_unlock(&lpfc_cmd->buf_lock); lpfc_release_scsi_buf(phba, lpfc_cmd); @@ -4463,7 +4461,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) { - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); if (cpu < LPFC_CHECK_CPU_CNT) { struct lpfc_sli4_hdw_queue *hdwq = &phba->sli4_hba.hdwq[lpfc_cmd->hdwq_no]; @@ -4718,6 +4716,9 @@ wait_for_cmpl: iocb->sli4_xritag, ret, cmnd->device->id, cmnd->device->lun); } + + lpfc_cmd->waitq = NULL; + spin_unlock(&lpfc_cmd->buf_lock); goto out; @@ -4797,7 +4798,12 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) rsp_info, rsp_len, rsp_info_code); - if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) { + /* If FCP_RSP_LEN_VALID bit is one, then the FCP_RSP_LEN + * field specifies the number of valid bytes of FCP_RSP_INFO. + * The FCP_RSP_LEN field shall be set to 0x04 or 0x08 + */ + if ((fcprsp->rspStatus2 & RSP_LEN_VALID) && + ((rsp_len == 8) || (rsp_len == 4))) { switch (rsp_info_code) { case RSP_NO_FAILURE: lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, @@ -5048,7 +5054,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata || !rdata->pnode) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0798 Device Reset rport failure: rdata x%p\n", + "0798 Device Reset rdata failure: rdata x%p\n", rdata); return FAILED; } @@ -5117,9 +5123,10 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) int status; rdata = lpfc_rport_data_from_scsi_device(cmnd->device); - if (!rdata) { + if (!rdata || !rdata->pnode) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0799 Target Reset rport failure: rdata x%p\n", rdata); + "0799 Target Reset rdata failure: rdata x%p\n", + rdata); return FAILED; } pnode = rdata->pnode; @@ -5740,7 +5747,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /* Create an lun info structure and add to list of luns */ lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun, - pri, false); + pri, true); if (lun_info) { lun_info->oas_enabled = true; lun_info->priority = pri; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 57b4a463b589..f9e6a135d656 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -87,9 +87,6 @@ static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe); static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba); static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba); -static int lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -111,7 +108,7 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) * endianness. This function can be called with or without * lock. **/ -void +static void lpfc_sli4_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt) { uint64_t *src = srcp; @@ -151,7 +148,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* sanity check on queue memory */ if (unlikely(!q)) return -ENOMEM; - temp_wqe = q->qe[q->host_index].wqe; + temp_wqe = lpfc_sli4_qe(q, q->host_index); /* If the host has not yet processed the next entry then we are done */ idx = ((q->host_index + 1) % q->entry_count); @@ -271,7 +268,7 @@ lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) /* sanity check on queue memory */ if (unlikely(!q)) return -ENOMEM; - temp_mqe = q->qe[q->host_index].mqe; + temp_mqe = lpfc_sli4_qe(q, q->host_index); /* If the host has not yet processed the next entry then we are done */ if (((q->host_index + 1) % q->entry_count) == q->hba_index) @@ -331,7 +328,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) /* sanity check on queue memory */ if (unlikely(!q)) return NULL; - eqe = q->qe[q->host_index].eqe; + eqe = lpfc_sli4_qe(q, q->host_index); /* If the next EQE is not valid then we are done */ if (bf_get_le32(lpfc_eqe_valid, eqe) != q->qe_valid) @@ -355,7 +352,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) * @q: The Event Queue to disable interrupts * **/ -inline void +void lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) { struct lpfc_register doorbell; @@ -374,7 +371,7 @@ lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) * @q: The Event Queue to disable interrupts * **/ -inline void +void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q) { struct lpfc_register doorbell; @@ -545,7 +542,7 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) /* sanity check on queue memory */ if (unlikely(!q)) return NULL; - cqe = q->qe[q->host_index].cqe; + cqe = lpfc_sli4_qe(q, q->host_index); /* If the next CQE is not valid then we are done */ if (bf_get_le32(lpfc_cqe_valid, cqe) != q->qe_valid) @@ -667,8 +664,8 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, return -ENOMEM; hq_put_index = hq->host_index; dq_put_index = dq->host_index; - temp_hrqe = hq->qe[hq_put_index].rqe; - temp_drqe = dq->qe[dq_put_index].rqe; + temp_hrqe = lpfc_sli4_qe(hq, hq_put_index); + temp_drqe = lpfc_sli4_qe(dq, dq_put_index); if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ) return -EINVAL; @@ -907,10 +904,10 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba) mod_timer(&phba->rrq_tmr, next_time); list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) { list_del(&rrq->list); - if (!rrq->send_rrq) + if (!rrq->send_rrq) { /* this call will free the rrq */ - lpfc_clr_rrq_active(phba, rrq->xritag, rrq); - else if (lpfc_send_rrq(phba, rrq)) { + lpfc_clr_rrq_active(phba, rrq->xritag, rrq); + } else if (lpfc_send_rrq(phba, rrq)) { /* if we send the rrq then the completion handler * will clear the bit in the xribitmap. */ @@ -994,15 +991,14 @@ lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * @ndlp: Targets nodelist pointer for this exchange. * @xritag the xri in the bitmap to test. * - * This function is called with hbalock held. This function - * returns 0 = rrq not active for this xri - * 1 = rrq is valid for this xri. + * This function returns: + * 0 = rrq not active for this xri + * 1 = rrq is valid for this xri. **/ int lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint16_t xritag) { - lockdep_assert_held(&phba->hbalock); if (!ndlp) return 0; if (!ndlp->active_rrqs_xri_bitmap) @@ -1105,10 +1101,11 @@ out: * @phba: Pointer to HBA context object. * @piocb: Pointer to the iocbq. * - * This function is called with the ring lock held. This function - * gets a new driver sglq object from the sglq list. If the - * list is not empty then it is successful, it returns pointer to the newly - * allocated sglq object else it returns NULL. + * The driver calls this function with either the nvme ls ring lock + * or the fc els ring lock held depending on the iocb usage. This function + * gets a new driver sglq object from the sglq list. If the list is not empty + * then it is successful, it returns pointer to the newly allocated sglq + * object else it returns NULL. **/ static struct lpfc_sglq * __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) @@ -1118,9 +1115,15 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) struct lpfc_sglq *start_sglq = NULL; struct lpfc_io_buf *lpfc_cmd; struct lpfc_nodelist *ndlp; + struct lpfc_sli_ring *pring = NULL; int found = 0; - lockdep_assert_held(&phba->hbalock); + if (piocbq->iocb_flag & LPFC_IO_NVME_LS) + pring = phba->sli4_hba.nvmels_wq->pring; + else + pring = lpfc_phba_elsring(phba); + + lockdep_assert_held(&pring->ring_lock); if (piocbq->iocb_flag & LPFC_IO_FCP) { lpfc_cmd = (struct lpfc_io_buf *) piocbq->context1; @@ -1563,7 +1566,8 @@ lpfc_sli_ring_map(struct lpfc_hba *phba) * @pring: Pointer to driver SLI ring object. * @piocb: Pointer to the driver iocb object. * - * This function is called with hbalock held. The function adds the + * The driver calls this function with the hbalock held for SLI3 ports or + * the ring lock held for SLI4 ports. The function adds the * new iocb to txcmplq of the given ring. This function always returns * 0. If this function is called for ELS ring, this function checks if * there is a vport associated with the ELS command. This function also @@ -1573,7 +1577,10 @@ static int lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { - lockdep_assert_held(&phba->hbalock); + if (phba->sli_rev == LPFC_SLI_REV4) + lockdep_assert_held(&pring->ring_lock); + else + lockdep_assert_held(&phba->hbalock); BUG_ON(!piocb); @@ -2502,8 +2509,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { ndlp->nlp_flag &= ~NLP_UNREG_INP; } + pmb->ctx_ndlp = NULL; } - pmb->ctx_ndlp = NULL; } /* Check security permission status on INIT_LINK mailbox command */ @@ -2970,8 +2977,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * * This function looks up the iocb_lookup table to get the command iocb * corresponding to the given response iocb using the iotag of the - * response iocb. This function is called with the hbalock held - * for sli3 devices or the ring_lock for sli4 devices. + * response iocb. The driver calls this function with the hbalock held + * for SLI3 ports or the ring lock held for SLI4 ports. * This function returns the command iocb object if it finds the command * iocb else returns NULL. **/ @@ -2982,8 +2989,15 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, { struct lpfc_iocbq *cmd_iocb = NULL; uint16_t iotag; - lockdep_assert_held(&phba->hbalock); + spinlock_t *temp_lock = NULL; + unsigned long iflag = 0; + + if (phba->sli_rev == LPFC_SLI_REV4) + temp_lock = &pring->ring_lock; + else + temp_lock = &phba->hbalock; + spin_lock_irqsave(temp_lock, iflag); iotag = prspiocb->iocb.ulpIoTag; if (iotag != 0 && iotag <= phba->sli.last_iotag) { @@ -2993,10 +3007,12 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, list_del_init(&cmd_iocb->list); cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; + spin_unlock_irqrestore(temp_lock, iflag); return cmd_iocb; } } + spin_unlock_irqrestore(temp_lock, iflag); lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0317 iotag x%x is out of " "range: max iotag x%x wd0 x%x\n", @@ -3012,8 +3028,8 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, * @iotag: IOCB tag. * * This function looks up the iocb_lookup table to get the command iocb - * corresponding to the given iotag. This function is called with the - * hbalock held. + * corresponding to the given iotag. The driver calls this function with + * the ring lock held because this function is an SLI4 port only helper. * This function returns the command iocb object if it finds the command * iocb else returns NULL. **/ @@ -3022,8 +3038,15 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint16_t iotag) { struct lpfc_iocbq *cmd_iocb = NULL; + spinlock_t *temp_lock = NULL; + unsigned long iflag = 0; - lockdep_assert_held(&phba->hbalock); + if (phba->sli_rev == LPFC_SLI_REV4) + temp_lock = &pring->ring_lock; + else + temp_lock = &phba->hbalock; + + spin_lock_irqsave(temp_lock, iflag); if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { @@ -3031,10 +3054,12 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, list_del_init(&cmd_iocb->list); cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; + spin_unlock_irqrestore(temp_lock, iflag); return cmd_iocb; } } + spin_unlock_irqrestore(temp_lock, iflag); lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0372 iotag x%x lookup error: max iotag (x%x) " "iocb_flag x%x\n", @@ -3068,17 +3093,7 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int rc = 1; unsigned long iflag; - /* Based on the iotag field, get the cmd IOCB from the txcmplq */ - if (phba->sli_rev == LPFC_SLI_REV4) - spin_lock_irqsave(&pring->ring_lock, iflag); - else - spin_lock_irqsave(&phba->hbalock, iflag); cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); - if (phba->sli_rev == LPFC_SLI_REV4) - spin_unlock_irqrestore(&pring->ring_lock, iflag); - else - spin_unlock_irqrestore(&phba->hbalock, iflag); - if (cmdiocbp) { if (cmdiocbp->iocb_cmpl) { /* @@ -3409,8 +3424,10 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, break; } + spin_unlock_irqrestore(&phba->hbalock, iflag); cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); + spin_lock_irqsave(&phba->hbalock, iflag); if (unlikely(!cmdiocbq)) break; if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) @@ -3604,9 +3621,12 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, case LPFC_ABORT_IOCB: cmdiocbp = NULL; - if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) + if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) { + spin_unlock_irqrestore(&phba->hbalock, iflag); cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); + spin_lock_irqsave(&phba->hbalock, iflag); + } if (cmdiocbp) { /* Call the specified completion routine */ if (cmdiocbp->iocb_cmpl) { @@ -3922,33 +3942,6 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) } /** - * lpfc_sli_abort_wqe_ring - Abort all iocbs in the ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function aborts all iocbs in the given ring and frees all the iocb - * objects in txq. This function issues an abort iocb for all the iocb commands - * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before - * the return of this function. The caller is not required to hold any locks. - **/ -void -lpfc_sli_abort_wqe_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - LIST_HEAD(completions); - struct lpfc_iocbq *iocb, *next_iocb; - - if (pring->ringno == LPFC_ELS_RING) - lpfc_fabric_abort_hba(phba); - - spin_lock_irq(&phba->hbalock); - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli4_abort_nvme_io(phba, pring, iocb); - spin_unlock_irq(&phba->hbalock); -} - - -/** * lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. @@ -3978,33 +3971,6 @@ lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba) } /** - * lpfc_sli_abort_nvme_rings - Abort all wqes in all NVME rings - * @phba: Pointer to HBA context object. - * - * This function aborts all wqes in NVME rings. This function issues an - * abort wqe for all the outstanding IO commands in txcmplq. The iocbs in - * the txcmplq is not guaranteed to complete before the return of this - * function. The caller is not required to hold any locks. - **/ -void -lpfc_sli_abort_nvme_rings(struct lpfc_hba *phba) -{ - struct lpfc_sli_ring *pring; - uint32_t i; - - if ((phba->sli_rev < LPFC_SLI_REV4) || - !(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) - return; - - /* Abort all IO on each NVME ring. */ - for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].nvme_wq->pring; - lpfc_sli_abort_wqe_ring(phba, pring); - } -} - - -/** * lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring * @phba: Pointer to HBA context object. * @@ -4487,7 +4453,9 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) } /* Turn off parity checking and serr during the physical reset */ - pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); + if (pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value)) + return -EIO; + pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); @@ -4564,7 +4532,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) "0389 Performing PCI function reset!\n"); /* Turn off parity checking and serr during the physical reset */ - pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); + if (pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value)) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3205 PCI read Config failed\n"); + return -EIO; + } + pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); @@ -5395,7 +5368,7 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, } /** - * lpfc_sli4_retrieve_pport_name - Retrieve SLI4 device physical port name + * lpfc_sli4_get_ctl_attr - Retrieve SLI4 device controller attributes * @phba: pointer to lpfc hba data structure. * * This routine retrieves SLI4 device physical port name this PCI function @@ -5403,40 +5376,30 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, * * Return codes * 0 - successful - * otherwise - failed to retrieve physical port name + * otherwise - failed to retrieve controller attributes **/ static int -lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) +lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) { LPFC_MBOXQ_t *mboxq; struct lpfc_mbx_get_cntl_attributes *mbx_cntl_attr; struct lpfc_controller_attribute *cntl_attr; - struct lpfc_mbx_get_port_name *get_port_name; void *virtaddr = NULL; uint32_t alloclen, reqlen; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; - char cport_name = 0; int rc; - /* We assume nothing at this point */ - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; - phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_NON; - mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) return -ENOMEM; - /* obtain link type and link number via READ_CONFIG */ - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; - lpfc_sli4_read_config(phba); - if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) - goto retrieve_ppname; - /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */ + /* Send COMMON_GET_CNTL_ATTRIBUTES mbox cmd */ reqlen = sizeof(struct lpfc_mbx_get_cntl_attributes); alloclen = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES, reqlen, LPFC_SLI4_MBX_NEMBED); + if (alloclen < reqlen) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3084 Allocated DMA memory size (%d) is " @@ -5462,16 +5425,71 @@ lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) rc = -ENXIO; goto out_free_mboxq; } + cntl_attr = &mbx_cntl_attr->cntl_attr; phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; phba->sli4_hba.lnk_info.lnk_tp = bf_get(lpfc_cntl_attr_lnk_type, cntl_attr); phba->sli4_hba.lnk_info.lnk_no = bf_get(lpfc_cntl_attr_lnk_numb, cntl_attr); + + memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion)); + strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str, + sizeof(phba->BIOSVersion)); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3086 lnk_type:%d, lnk_numb:%d\n", + "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s\n", phba->sli4_hba.lnk_info.lnk_tp, - phba->sli4_hba.lnk_info.lnk_no); + phba->sli4_hba.lnk_info.lnk_no, + phba->BIOSVersion); +out_free_mboxq: + if (rc != MBX_TIMEOUT) { + if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) + lpfc_sli4_mbox_cmd_free(phba, mboxq); + else + mempool_free(mboxq, phba->mbox_mem_pool); + } + return rc; +} + +/** + * lpfc_sli4_retrieve_pport_name - Retrieve SLI4 device physical port name + * @phba: pointer to lpfc hba data structure. + * + * This routine retrieves SLI4 device physical port name this PCI function + * is attached to. + * + * Return codes + * 0 - successful + * otherwise - failed to retrieve physical port name + **/ +static int +lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + struct lpfc_mbx_get_port_name *get_port_name; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + char cport_name = 0; + int rc; + + /* We assume nothing at this point */ + phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; + phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_NON; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + /* obtain link type and link number via READ_CONFIG */ + phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; + lpfc_sli4_read_config(phba); + if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) + goto retrieve_ppname; + + /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */ + rc = lpfc_sli4_get_ctl_attr(phba); + if (rc) + goto out_free_mboxq; retrieve_ppname: lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, @@ -5553,6 +5571,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) int qidx; struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba; struct lpfc_sli4_hdw_queue *qp; + struct lpfc_queue *eq; sli4_hba->sli4_write_cq_db(phba, sli4_hba->mbx_cq, 0, LPFC_QUEUE_REARM); sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM); @@ -5560,18 +5579,24 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0, LPFC_QUEUE_REARM); - qp = sli4_hba->hdwq; if (sli4_hba->hdwq) { + /* Loop thru all Hardware Queues */ for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - sli4_hba->sli4_write_cq_db(phba, qp[qidx].fcp_cq, 0, + qp = &sli4_hba->hdwq[qidx]; + /* ARM the corresponding CQ */ + sli4_hba->sli4_write_cq_db(phba, qp->fcp_cq, 0, LPFC_QUEUE_REARM); - sli4_hba->sli4_write_cq_db(phba, qp[qidx].nvme_cq, 0, + sli4_hba->sli4_write_cq_db(phba, qp->nvme_cq, 0, LPFC_QUEUE_REARM); } - for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) - sli4_hba->sli4_write_eq_db(phba, qp[qidx].hba_eq, - 0, LPFC_QUEUE_REARM); + /* Loop thru all IRQ vectors */ + for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { + eq = sli4_hba->hba_eq_hdl[qidx].eq; + /* ARM the corresponding EQ */ + sli4_hba->sli4_write_eq_db(phba, eq, + 0, LPFC_QUEUE_REARM); + } } if (phba->nvmet_support) { @@ -7047,7 +7072,7 @@ lpfc_sli4_repost_sgl_list(struct lpfc_hba *phba, * * Returns: 0 = success, non-zero failure. **/ -int +static int lpfc_sli4_repost_io_sgl_list(struct lpfc_hba *phba) { LIST_HEAD(post_nblist); @@ -7067,7 +7092,7 @@ lpfc_sli4_repost_io_sgl_list(struct lpfc_hba *phba) return rc; } -void +static void lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) { uint32_t len; @@ -7250,6 +7275,12 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "3080 Successful retrieving SLI4 device " "physical port name: %s.\n", phba->Port); + rc = lpfc_sli4_get_ctl_attr(phba); + if (!rc) + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "8351 Successful retrieving SLI4 device " + "CTL ATTR\n"); + /* * Evaluate the read rev and vpd data. Populate the driver * state with the results. If this routine fails, the failure @@ -7652,12 +7683,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->cfg_xri_rebalancing = 0; } - /* Arm the CQs and then EQs on device */ - lpfc_sli4_arm_cqeq_intr(phba); - - /* Indicate device interrupt mode */ - phba->sli4_hba.intr_enable = 1; - /* Allow asynchronous mailbox command to go through */ spin_lock_irq(&phba->hbalock); phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; @@ -7726,6 +7751,12 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->trunk_link.link3.state = LPFC_LINK_DOWN; spin_unlock_irq(&phba->hbalock); + /* Arm the CQs and then EQs on device */ + lpfc_sli4_arm_cqeq_intr(phba); + + /* Indicate device interrupt mode */ + phba->sli4_hba.intr_enable = 1; + if (!(phba->hba_flag & HBA_FCOE_MODE) && (phba->hba_flag & LINK_DISABLED)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, @@ -7820,8 +7851,9 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) mcq = phba->sli4_hba.mbx_cq; idx = mcq->hba_index; 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; + while (bf_get_le32(lpfc_cqe_valid, + (struct lpfc_cqe *)lpfc_sli4_qe(mcq, idx)) == qe_valid) { + mcqe = (struct lpfc_mcqe *)(lpfc_sli4_qe(mcq, idx)); if (bf_get_le32(lpfc_trailer_completed, mcqe) && (!bf_get_le32(lpfc_trailer_async, mcqe))) { pending_completions = true; @@ -7850,26 +7882,28 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) * and will process all the completions associated with the eq for the * mailbox completion queue. **/ -bool +static 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_queue *eq; bool mbox_pending; if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4)) return false; - /* Find the eq associated with the mcq */ - - if (sli4_hba->hdwq) - for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) - if (sli4_hba->hdwq[eqidx].hba_eq->queue_id == - sli4_hba->mbx_cq->assoc_qid) { - fpeq = sli4_hba->hdwq[eqidx].hba_eq; + /* Find the EQ associated with the mbox CQ */ + if (sli4_hba->hdwq) { + for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) { + eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq; + if (eq->queue_id == sli4_hba->mbx_cq->assoc_qid) { + fpeq = eq; break; } + } + } if (!fpeq) return false; @@ -8500,7 +8534,7 @@ lpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); if (!db_ready) - msleep(2); + mdelay(2); if (time_after(jiffies, timeout)) return MBXERR_ERROR; @@ -9373,6 +9407,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_RSCN_XMT || *pcmd == ELS_CMD_FDISC || *pcmd == ELS_CMD_LOGO || *pcmd == ELS_CMD_PLOGI)) { @@ -11264,102 +11299,6 @@ abort_iotag_exit: } /** - * lpfc_sli4_abort_nvme_io - Issue abort for a command iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @cmdiocb: Pointer to driver command iocb object. - * - * This function issues an abort iocb for the provided command iocb down to - * the port. Other than the case the outstanding command iocb is an abort - * request, this function issues abort out unconditionally. This function is - * called with hbalock held. The function returns 0 when it fails due to - * memory allocation failure or when the command iocb is an abort request. - **/ -static int -lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct lpfc_iocbq *abtsiocbp; - union lpfc_wqe128 *abts_wqe; - int retval; - int idx = cmdiocb->hba_wqidx; - - /* - * There are certain command types we don't want to abort. And we - * don't want to abort commands that are already in the process of - * being aborted. - */ - if (cmdiocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - cmdiocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; - - /* issue ABTS for this io based on iotag */ - abtsiocbp = __lpfc_sli_get_iocbq(phba); - if (abtsiocbp == NULL) - return 0; - - /* This signals the response to set the correct status - * before calling the completion handler - */ - cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; - - /* Complete prepping the abort wqe and issue to the FW. */ - abts_wqe = &abtsiocbp->wqe; - - /* Clear any stale WQE contents */ - memset(abts_wqe, 0, sizeof(union lpfc_wqe)); - bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); - - /* word 7 */ - bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - bf_set(wqe_class, &abts_wqe->abort_cmd.wqe_com, - cmdiocb->iocb.ulpClass); - - /* word 8 - tell the FW to abort the IO associated with this - * outstanding exchange ID. - */ - abts_wqe->abort_cmd.wqe_com.abort_tag = cmdiocb->sli4_xritag; - - /* word 9 - this is the iotag for the abts_wqe completion. */ - bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com, - abtsiocbp->iotag); - - /* word 10 */ - bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - /* word 11 */ - bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocbp->iocb_flag |= LPFC_IO_NVME; - abtsiocbp->vport = vport; - abtsiocbp->wqe_cmpl = lpfc_nvme_abort_fcreq_cmpl; - retval = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[idx], - abtsiocbp); - if (retval) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME, - "6147 Failed abts issue_wqe with status x%x " - "for oxid x%x\n", - retval, cmdiocb->sli4_xritag); - lpfc_sli_release_iocbq(phba, abtsiocbp); - return retval; - } - - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME, - "6148 Drv Abort NVME Request Issued for " - "ox_id x%x on reqtag x%x\n", - cmdiocb->sli4_xritag, - abtsiocbp->iotag); - - return retval; -} - -/** * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba. * @phba: pointer to lpfc HBA data structure. * @@ -13070,13 +13009,11 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return NULL; wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; - spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; /* Look up the ELS command IOCB and create pseudo response IOCB */ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); if (unlikely(!cmdiocbq)) { - spin_unlock_irqrestore(&pring->ring_lock, iflags); lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0386 ELS complete with no corresponding " "cmdiocb: 0x%x 0x%x 0x%x 0x%x\n", @@ -13086,6 +13023,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return NULL; } + spin_lock_irqsave(&pring->ring_lock, iflags); /* Put the iocb back on the txcmplq */ lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq); spin_unlock_irqrestore(&pring->ring_lock, iflags); @@ -13636,7 +13574,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0390 Cannot schedule soft IRQ " "for CQ eqcqid=%d, cqid=%d on CPU %d\n", - cqid, cq->queue_id, smp_processor_id()); + cqid, cq->queue_id, raw_smp_processor_id()); } /** @@ -13676,14 +13614,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, goto rearm_and_exit; /* Process all the entries to the CQ */ + cq->q_flag = 0; cqe = lpfc_sli4_cq_get(cq); while (cqe) { -#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) && defined(BUILD_NVME) - if (phba->ktime_on) - cq->isr_timestamp = ktime_get_ns(); - else - cq->isr_timestamp = 0; -#endif workposted |= handler(phba, cq, cqe); __lpfc_sli4_consume_cqe(phba, cq, cqe); @@ -13697,6 +13630,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, consumed = 0; } + if (count == LPFC_NVMET_CQ_NOTIFY) + cq->q_flag |= HBA_NVMET_CQ_NOTIFY; + cqe = lpfc_sli4_cq_get(cq); } if (count >= phba->cfg_cq_poll_threshold) { @@ -13856,9 +13792,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Look up the FCP command IOCB and create pseudo response IOCB */ spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; + spin_unlock_irqrestore(&pring->ring_lock, iflags); cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0374 FCP complete with no corresponding " @@ -14012,14 +13948,14 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, goto drop; if (fc_hdr->fh_type == FC_TYPE_FCP) { - dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe); + dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe); lpfc_nvmet_unsol_fcp_event( - phba, idx, dma_buf, - cq->isr_timestamp); + phba, idx, dma_buf, cq->isr_timestamp, + cq->q_flag & HBA_NVMET_CQ_NOTIFY); return false; } drop: - lpfc_in_buf_free(phba, &dma_buf->dbuf); + lpfc_rq_buf_free(phba, &dma_buf->hbuf); break; case FC_STATUS_INSUFF_BUF_FRM_DISC: if (phba->nvmet_support) { @@ -14181,11 +14117,17 @@ process_cq: } work_cq: +#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) + if (phba->ktime_on) + cq->isr_timestamp = ktime_get_ns(); + else + cq->isr_timestamp = 0; +#endif if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork)) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0363 Cannot schedule soft IRQ " "for CQ eqcqid=%d, cqid=%d on CPU %d\n", - cqid, cq->queue_id, smp_processor_id()); + cqid, cq->queue_id, raw_smp_processor_id()); } /** @@ -14307,7 +14249,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) return IRQ_NONE; /* Get to the EQ struct associated with this vector */ - fpeq = phba->sli4_hba.hdwq[hba_eqidx].hba_eq; + fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq; if (unlikely(!fpeq)) return IRQ_NONE; @@ -14324,7 +14266,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) eqi = phba->sli4_hba.eq_info; icnt = this_cpu_inc_return(eqi->icnt); - fpeq->last_cpu = smp_processor_id(); + fpeq->last_cpu = raw_smp_processor_id(); if (icnt > LPFC_EQD_ISR_TRIGGER && phba->cfg_irq_chann == 1 && @@ -14410,6 +14352,9 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) if (!queue) return; + if (!list_empty(&queue->wq_list)) + list_del(&queue->wq_list); + while (!list_empty(&queue->page_list)) { list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf, list); @@ -14425,9 +14370,6 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) if (!list_empty(&queue->cpu_list)) list_del(&queue->cpu_list); - if (!list_empty(&queue->wq_list)) - list_del(&queue->wq_list); - kfree(queue); return; } @@ -14438,6 +14380,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) * @page_size: The size of a queue page * @entry_size: The size of each queue entry for this queue. * @entry count: The number of entries that this queue will handle. + * @cpu: The cpu that will primarily utilize this queue. * * This function allocates a queue structure and the DMAable memory used for * the host resident queue. This function must be called before creating the @@ -14445,28 +14388,26 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) **/ struct lpfc_queue * lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, - uint32_t entry_size, uint32_t entry_count) + uint32_t entry_size, uint32_t entry_count, int cpu) { struct lpfc_queue *queue; struct lpfc_dmabuf *dmabuf; - int x, total_qe_count; - void *dma_pointer; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + uint16_t x, pgcnt; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = page_size; - queue = kzalloc(sizeof(struct lpfc_queue) + - (sizeof(union sli4_qe) * entry_count), GFP_KERNEL); - if (!queue) - return NULL; - queue->page_count = (ALIGN(entry_size * entry_count, - hw_page_size))/hw_page_size; + pgcnt = ALIGN(entry_size * entry_count, hw_page_size) / hw_page_size; /* If needed, Adjust page count to match the max the adapter supports */ - if (phba->sli4_hba.pc_sli4_params.wqpcnt && - (queue->page_count > phba->sli4_hba.pc_sli4_params.wqpcnt)) - queue->page_count = phba->sli4_hba.pc_sli4_params.wqpcnt; + if (pgcnt > phba->sli4_hba.pc_sli4_params.wqpcnt) + pgcnt = phba->sli4_hba.pc_sli4_params.wqpcnt; + + queue = kzalloc_node(sizeof(*queue) + (sizeof(void *) * pgcnt), + GFP_KERNEL, cpu_to_node(cpu)); + if (!queue) + return NULL; INIT_LIST_HEAD(&queue->list); INIT_LIST_HEAD(&queue->wq_list); @@ -14478,13 +14419,17 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, /* Set queue parameters now. If the system cannot provide memory * resources, the free routine needs to know what was allocated. */ + queue->page_count = pgcnt; + queue->q_pgs = (void **)&queue[1]; + queue->entry_cnt_per_pg = hw_page_size / entry_size; queue->entry_size = entry_size; queue->entry_count = entry_count; queue->page_size = hw_page_size; queue->phba = phba; - for (x = 0, total_qe_count = 0; x < queue->page_count; x++) { - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + for (x = 0; x < queue->page_count; x++) { + dmabuf = kzalloc_node(sizeof(*dmabuf), GFP_KERNEL, + dev_to_node(&phba->pcidev->dev)); if (!dmabuf) goto out_fail; dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, @@ -14496,13 +14441,8 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, } dmabuf->buffer_tag = x; list_add_tail(&dmabuf->list, &queue->page_list); - /* initialize queue's entry array */ - dma_pointer = dmabuf->virt; - for (; total_qe_count < entry_count && - dma_pointer < (hw_page_size + dmabuf->virt); - total_qe_count++, dma_pointer += entry_size) { - queue->qe[total_qe_count].address = dma_pointer; - } + /* use lpfc_sli4_qe to index a paritcular entry in this page */ + queue->q_pgs[x] = dmabuf->virt; } INIT_WORK(&queue->irqwork, lpfc_sli4_hba_process_cq); INIT_WORK(&queue->spwork, lpfc_sli4_sp_process_cq); @@ -14594,7 +14534,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, /* set values by EQ_DELAY register if supported */ if (phba->sli.sli_flag & LPFC_SLI_USE_EQDR) { for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) { - eq = phba->sli4_hba.hdwq[qidx].hba_eq; + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; if (!eq) continue; @@ -14603,7 +14543,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, if (++cnt >= numq) break; } - return; } @@ -14631,7 +14570,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, dmult = LPFC_DMULT_MAX; for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) { - eq = phba->sli4_hba.hdwq[qidx].hba_eq; + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; if (!eq) continue; eq->q_mode = usdelay; @@ -14733,8 +14672,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0360 Unsupported EQ count. (%d)\n", eq->entry_count); - if (eq->entry_count < 256) - return -EINVAL; + if (eq->entry_count < 256) { + status = -EINVAL; + goto out; + } /* fall through - otherwise default to smallest count */ case 256: bf_set(lpfc_eq_context_count, &eq_create->u.request.context, @@ -14786,7 +14727,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) eq->host_index = 0; eq->notify_interval = LPFC_EQ_NOTIFY_INTRVL; eq->max_proc_limit = LPFC_EQ_MAX_PROC_LIMIT; - +out: mempool_free(mbox, phba->mbox_mem_pool); return status; } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 7a1a761efdd6..467b8270f7fd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -327,6 +327,10 @@ struct lpfc_sli { #define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */ #define LPFC_SLI_SUPPRESS_RSP 0x4000 /* Suppress RSP feature is supported */ #define LPFC_SLI_USE_EQDR 0x8000 /* EQ Delay Register is supported */ +#define LPFC_QUEUE_FREE_INIT 0x10000 /* Queue freeing is in progress */ +#define LPFC_QUEUE_FREE_WAIT 0x20000 /* Hold Queue free as it is being + * used outside worker thread + */ struct lpfc_sli_ring *sli3_ring; @@ -427,14 +431,13 @@ struct lpfc_io_buf { struct { struct nvmefc_fcp_req *nvmeCmd; uint16_t qidx; - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint64_t ts_cmd_start; - uint64_t ts_last_cmd; - uint64_t ts_cmd_wqput; - uint64_t ts_isr_cmpl; - uint64_t ts_data_nvme; -#endif }; }; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + uint64_t ts_cmd_start; + uint64_t ts_last_cmd; + uint64_t ts_cmd_wqput; + uint64_t ts_isr_cmpl; + uint64_t ts_data_nvme; +#endif }; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 40c85091c805..3aeca387b22a 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -117,21 +117,6 @@ enum lpfc_sli4_queue_subtype { LPFC_USOL }; -union sli4_qe { - void *address; - struct lpfc_eqe *eqe; - struct lpfc_cqe *cqe; - struct lpfc_mcqe *mcqe; - struct lpfc_wcqe_complete *wcqe_complete; - struct lpfc_wcqe_release *wcqe_release; - struct sli4_wcqe_xri_aborted *wcqe_xri_aborted; - struct lpfc_rcqe_complete *rcqe_complete; - struct lpfc_mqe *mqe; - union lpfc_wqe *wqe; - union lpfc_wqe128 *wqe128; - struct lpfc_rqe *rqe; -}; - /* RQ buffer list */ struct lpfc_rqb { uint16_t entry_count; /* Current number of RQ slots */ @@ -157,6 +142,7 @@ struct lpfc_queue { struct list_head cpu_list; uint32_t entry_count; /* Number of entries to support on the queue */ uint32_t entry_size; /* Size of each queue entry. */ + uint32_t entry_cnt_per_pg; uint32_t notify_interval; /* Queue Notification Interval * For chip->host queues (EQ, CQ, RQ): * specifies the interval (number of @@ -211,6 +197,8 @@ struct lpfc_queue { #define LPFC_DB_LIST_FORMAT 0x02 uint8_t q_flag; #define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */ +#define HBA_NVMET_CQ_NOTIFY 0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */ +#define LPFC_NVMET_CQ_NOTIFY 4 void __iomem *db_regaddr; uint16_t dpp_enable; uint16_t dpp_id; @@ -254,17 +242,17 @@ struct lpfc_queue { uint16_t last_cpu; /* most recent cpu */ uint8_t qe_valid; struct lpfc_queue *assoc_qp; - union sli4_qe qe[1]; /* array to index entries (must be last) */ + void **q_pgs; /* array to index entries per page */ }; struct lpfc_sli4_link { - uint16_t speed; + uint32_t speed; uint8_t duplex; uint8_t status; uint8_t type; uint8_t number; uint8_t fault; - uint16_t logical_speed; + uint32_t logical_speed; uint16_t topology; }; @@ -464,6 +452,7 @@ struct lpfc_hba_eq_hdl { uint32_t idx; char handler_name[LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba *phba; + struct lpfc_queue *eq; }; /*BB Credit recovery value*/ @@ -526,6 +515,7 @@ struct lpfc_pc_sli4_params { #define LPFC_WQ_SZ64_SUPPORT 1 #define LPFC_WQ_SZ128_SUPPORT 2 uint8_t wqpcnt; + uint8_t nvme; }; #define LPFC_CQ_4K_PAGE_SZ 0x1 @@ -543,8 +533,9 @@ struct lpfc_sli4_lnk_info { #define LPFC_LNK_DAT_INVAL 0 #define LPFC_LNK_DAT_VAL 1 uint8_t lnk_tp; -#define LPFC_LNK_GE 0x0 /* FCoE */ -#define LPFC_LNK_FC 0x1 /* FC */ +#define LPFC_LNK_GE 0x0 /* FCoE */ +#define LPFC_LNK_FC 0x1 /* FC */ +#define LPFC_LNK_FC_TRUNKED 0x2 /* FC_Trunked */ uint8_t lnk_no; uint8_t optic_state; }; @@ -559,7 +550,10 @@ struct lpfc_vector_map_info { uint16_t irq; uint16_t eq; uint16_t hdwq; - uint16_t hyper; + uint16_t flag; +#define LPFC_CPU_MAP_HYPER 0x1 +#define LPFC_CPU_MAP_UNASSIGN 0x2 +#define LPFC_CPU_FIRST_IRQ 0x4 }; #define LPFC_VECTOR_MAP_EMPTY 0xffff @@ -856,6 +850,8 @@ struct lpfc_sli4_hba { struct list_head lpfc_nvmet_sgl_list; spinlock_t abts_nvmet_buf_list_lock; /* list of aborted NVMET IOs */ struct list_head lpfc_abts_nvmet_ctx_list; + spinlock_t t_active_list_lock; /* list of active NVMET IOs */ + struct list_head t_active_ctx_list; struct list_head lpfc_nvmet_io_wait_list; struct lpfc_nvmet_ctx_info *nvmet_ctx_info; struct lpfc_sglq **lpfc_sglq_active_list; @@ -907,6 +903,18 @@ struct lpfc_sli4_hba { #define lpfc_conf_trunk_port3_WORD conf_trunk #define lpfc_conf_trunk_port3_SHIFT 3 #define lpfc_conf_trunk_port3_MASK 0x1 +#define lpfc_conf_trunk_port0_nd_WORD conf_trunk +#define lpfc_conf_trunk_port0_nd_SHIFT 4 +#define lpfc_conf_trunk_port0_nd_MASK 0x1 +#define lpfc_conf_trunk_port1_nd_WORD conf_trunk +#define lpfc_conf_trunk_port1_nd_SHIFT 5 +#define lpfc_conf_trunk_port1_nd_MASK 0x1 +#define lpfc_conf_trunk_port2_nd_WORD conf_trunk +#define lpfc_conf_trunk_port2_nd_SHIFT 6 +#define lpfc_conf_trunk_port2_nd_MASK 0x1 +#define lpfc_conf_trunk_port3_nd_WORD conf_trunk +#define lpfc_conf_trunk_port3_nd_SHIFT 7 +#define lpfc_conf_trunk_port3_nd_MASK 0x1 }; enum lpfc_sge_type { @@ -990,8 +998,10 @@ int lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *, struct lpfcMboxq *, uint16_t); void lpfc_sli4_hba_reset(struct lpfc_hba *); -struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, - uint32_t, uint32_t); +struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *phba, + uint32_t page_size, + uint32_t entry_size, + uint32_t entry_count, int cpu); void lpfc_sli4_queue_free(struct lpfc_queue *); int lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint32_t); void lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, @@ -1057,12 +1067,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 *); +void lpfc_sli4_eq_clr_intr(struct lpfc_queue *); void lpfc_sli4_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q, uint32_t count, bool arm); void lpfc_sli4_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q, uint32_t count, bool arm); -inline void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q); +void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q); void lpfc_sli4_if6_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q, uint32_t count, bool arm); void lpfc_sli4_if6_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q, @@ -1079,3 +1089,8 @@ int lpfc_sli4_post_status_check(struct lpfc_hba *); uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *); uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_ras_dma_free(struct lpfc_hba *phba); +static inline void *lpfc_sli4_qe(struct lpfc_queue *q, uint16_t idx) +{ + return q->q_pgs[idx / q->entry_cnt_per_pg] + + (q->entry_size * (idx % q->entry_cnt_per_pg)); +} diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 43fd693cf042..f7e93aaf1e00 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.2.0.0" +#define LPFC_DRIVER_VERSION "12.2.0.3" #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-2018 Broadcom. All Rights " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2019 Broadcom. All Rights " \ "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ "and/or its subsidiaries." diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index c8e6ae98a4a6..35d3e322d6d5 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI low-level driver for the 53c94 SCSI bus adaptor found * on Power Macintosh computers, controlling the external SCSI chain. diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index ee741207fd4e..1c78bc10c790 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* mac_esp.c: ESP front-end for Macintosh Quadra systems. * * Adapted from jazz_esp.c and the old mac_esp.c. diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 8b4b5b1a13d7..9c5566217ef6 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -1,8 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Generic Macintosh NCR5380 driver * * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov> * + * Copyright 2019 Finn Thain + * * derived in part from: */ /* @@ -11,6 +14,7 @@ * Copyright 1995, Russell King */ +#include <linux/delay.h> #include <linux/types.h> #include <linux/module.h> #include <linux/ioport.h> @@ -21,6 +25,7 @@ #include <asm/hwtest.h> #include <asm/io.h> +#include <asm/macintosh.h> #include <asm/macints.h> #include <asm/setup.h> @@ -52,7 +57,7 @@ static int setup_cmd_per_lun = -1; module_param(setup_cmd_per_lun, int, 0); static int setup_sg_tablesize = -1; module_param(setup_sg_tablesize, int, 0); -static int setup_use_pdma = -1; +static int setup_use_pdma = 512; module_param(setup_use_pdma, int, 0); static int setup_hostid = -1; module_param(setup_hostid, int, 0); @@ -89,223 +94,318 @@ static int __init mac_scsi_setup(char *str) __setup("mac5380=", mac_scsi_setup); #endif /* !MODULE */ -/* Pseudo DMA asm originally by Ove Edlund */ - -#define CP_IO_TO_MEM(s,d,n) \ -__asm__ __volatile__ \ - (" cmp.w #4,%2\n" \ - " bls 8f\n" \ - " move.w %1,%%d0\n" \ - " neg.b %%d0\n" \ - " and.w #3,%%d0\n" \ - " sub.w %%d0,%2\n" \ - " bra 2f\n" \ - " 1: move.b (%0),(%1)+\n" \ - " 2: dbf %%d0,1b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #5,%%d0\n" \ - " bra 4f\n" \ - " 3: move.l (%0),(%1)+\n" \ - "31: move.l (%0),(%1)+\n" \ - "32: move.l (%0),(%1)+\n" \ - "33: move.l (%0),(%1)+\n" \ - "34: move.l (%0),(%1)+\n" \ - "35: move.l (%0),(%1)+\n" \ - "36: move.l (%0),(%1)+\n" \ - "37: move.l (%0),(%1)+\n" \ - " 4: dbf %%d0,3b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #2,%%d0\n" \ - " and.w #7,%%d0\n" \ - " bra 6f\n" \ - " 5: move.l (%0),(%1)+\n" \ - " 6: dbf %%d0,5b\n" \ - " and.w #3,%2\n" \ - " bra 8f\n" \ - " 7: move.b (%0),(%1)+\n" \ - " 8: dbf %2,7b\n" \ - " moveq.l #0, %2\n" \ - " 9: \n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "91: moveq.l #1, %2\n" \ - " jra 9b\n" \ - "94: moveq.l #4, %2\n" \ - " jra 9b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,91b\n" \ - " .long 3b,94b\n" \ - " .long 31b,94b\n" \ - " .long 32b,94b\n" \ - " .long 33b,94b\n" \ - " .long 34b,94b\n" \ - " .long 35b,94b\n" \ - " .long 36b,94b\n" \ - " .long 37b,94b\n" \ - " .long 5b,94b\n" \ - " .long 7b,91b\n" \ - ".previous" \ - : "=a"(s), "=a"(d), "=d"(n) \ - : "0"(s), "1"(d), "2"(n) \ - : "d0") +/* + * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to + * specify the number of bytes between the delays expected from a SCSI target. + * This allows the operating system to "prevent bus errors when a target fails + * to deliver the next byte within the processor bus error timeout period." + * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets + * so bus errors are unavoidable. + * + * If a MOVE.B instruction faults, we assume that zero bytes were transferred + * and simply retry. That assumption probably depends on target behaviour but + * seems to hold up okay. The NOP provides synchronization: without it the + * fault can sometimes occur after the program counter has moved past the + * offending instruction. Post-increment addressing can't be used. + */ + +#define MOVE_BYTE(operands) \ + asm volatile ( \ + "1: moveb " operands " \n" \ + "11: nop \n" \ + " addq #1,%0 \n" \ + " subq #1,%1 \n" \ + "40: \n" \ + " \n" \ + ".section .fixup,\"ax\" \n" \ + ".even \n" \ + "90: movel #1, %2 \n" \ + " jra 40b \n" \ + ".previous \n" \ + " \n" \ + ".section __ex_table,\"a\" \n" \ + ".align 4 \n" \ + ".long 1b,90b \n" \ + ".long 11b,90b \n" \ + ".previous \n" \ + : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) + +/* + * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because + * the residual byte count would be uncertain. In that situation the MOVE_WORD + * macro clears n in the fixup section to abort the transfer. + */ + +#define MOVE_WORD(operands) \ + asm volatile ( \ + "1: movew " operands " \n" \ + "11: nop \n" \ + " subq #2,%1 \n" \ + "40: \n" \ + " \n" \ + ".section .fixup,\"ax\" \n" \ + ".even \n" \ + "90: movel #0, %1 \n" \ + " movel #2, %2 \n" \ + " jra 40b \n" \ + ".previous \n" \ + " \n" \ + ".section __ex_table,\"a\" \n" \ + ".align 4 \n" \ + ".long 1b,90b \n" \ + ".long 11b,90b \n" \ + ".previous \n" \ + : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) + +#define MOVE_16_WORDS(operands) \ + asm volatile ( \ + "1: movew " operands " \n" \ + "2: movew " operands " \n" \ + "3: movew " operands " \n" \ + "4: movew " operands " \n" \ + "5: movew " operands " \n" \ + "6: movew " operands " \n" \ + "7: movew " operands " \n" \ + "8: movew " operands " \n" \ + "9: movew " operands " \n" \ + "10: movew " operands " \n" \ + "11: movew " operands " \n" \ + "12: movew " operands " \n" \ + "13: movew " operands " \n" \ + "14: movew " operands " \n" \ + "15: movew " operands " \n" \ + "16: movew " operands " \n" \ + "17: nop \n" \ + " subl #32,%1 \n" \ + "40: \n" \ + " \n" \ + ".section .fixup,\"ax\" \n" \ + ".even \n" \ + "90: movel #0, %1 \n" \ + " movel #2, %2 \n" \ + " jra 40b \n" \ + ".previous \n" \ + " \n" \ + ".section __ex_table,\"a\" \n" \ + ".align 4 \n" \ + ".long 1b,90b \n" \ + ".long 2b,90b \n" \ + ".long 3b,90b \n" \ + ".long 4b,90b \n" \ + ".long 5b,90b \n" \ + ".long 6b,90b \n" \ + ".long 7b,90b \n" \ + ".long 8b,90b \n" \ + ".long 9b,90b \n" \ + ".long 10b,90b \n" \ + ".long 11b,90b \n" \ + ".long 12b,90b \n" \ + ".long 13b,90b \n" \ + ".long 14b,90b \n" \ + ".long 15b,90b \n" \ + ".long 16b,90b \n" \ + ".long 17b,90b \n" \ + ".previous \n" \ + : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) + +#define MAC_PDMA_DELAY 32 + +static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n) +{ + unsigned char *addr = start; + int result = 0; + + if (n >= 1) { + MOVE_BYTE("%3@,%0@"); + if (result) + goto out; + } + if (n >= 1 && ((unsigned long)addr & 1)) { + MOVE_BYTE("%3@,%0@"); + if (result) + goto out; + } + while (n >= 32) + MOVE_16_WORDS("%3@,%0@+"); + while (n >= 2) + MOVE_WORD("%3@,%0@+"); + if (result) + return start - addr; /* Negated to indicate uncertain length */ + if (n == 1) + MOVE_BYTE("%3@,%0@"); +out: + return addr - start; +} + +static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n) +{ + unsigned char *addr = start; + int result = 0; + + if (n >= 1) { + MOVE_BYTE("%0@,%3@"); + if (result) + goto out; + } + if (n >= 1 && ((unsigned long)addr & 1)) { + MOVE_BYTE("%0@,%3@"); + if (result) + goto out; + } + while (n >= 32) + MOVE_16_WORDS("%0@+,%3@"); + while (n >= 2) + MOVE_WORD("%0@+,%3@"); + if (result) + return start - addr; /* Negated to indicate uncertain length */ + if (n == 1) + MOVE_BYTE("%0@,%3@"); +out: + return addr - start; +} + +/* The "SCSI DMA" chip on the IIfx implements this register. */ +#define CTRL_REG 0x8 +#define CTRL_INTERRUPTS_ENABLE BIT(1) +#define CTRL_HANDSHAKE_MODE BIT(3) + +static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value) +{ + out_be32(hostdata->io + (CTRL_REG << 4), value); +} static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, unsigned char *dst, int len) { u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4); unsigned char *d = dst; - int n = len; - int transferred; + int result = 0; + + hostdata->pdma_residual = len; while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_DRQ | BASR_PHASE_MATCH, BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { - CP_IO_TO_MEM(s, d, n); + int bytes; + + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | + CTRL_INTERRUPTS_ENABLE); - transferred = d - dst - n; - hostdata->pdma_residual = len - transferred; + bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512)); - /* No bus error. */ - if (n == 0) - return 0; + if (bytes > 0) { + d += bytes; + hostdata->pdma_residual -= bytes; + } + + if (hostdata->pdma_residual == 0) + goto out; - /* Target changed phase early? */ if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, - BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0) - scmd_printk(KERN_ERR, hostdata->connected, + BUS_AND_STATUS_REG, BASR_ACK, + BASR_ACK, HZ / 64) < 0) + scmd_printk(KERN_DEBUG, hostdata->connected, "%s: !REQ and !ACK\n", __func__); if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) - return 0; + goto out; + + if (bytes == 0) + udelay(MAC_PDMA_DELAY); + + if (bytes >= 0) + continue; dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, - "%s: bus error (%d/%d)\n", __func__, transferred, len); + "%s: bus error (%d/%d)\n", __func__, d - dst, len); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - d = dst + transferred; - n = len - transferred; + result = -1; + goto out; } scmd_printk(KERN_ERR, hostdata->connected, "%s: phase mismatch or !DRQ\n", __func__); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - return -1; + result = -1; +out: + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); + return result; } - -#define CP_MEM_TO_IO(s,d,n) \ -__asm__ __volatile__ \ - (" cmp.w #4,%2\n" \ - " bls 8f\n" \ - " move.w %0,%%d0\n" \ - " neg.b %%d0\n" \ - " and.w #3,%%d0\n" \ - " sub.w %%d0,%2\n" \ - " bra 2f\n" \ - " 1: move.b (%0)+,(%1)\n" \ - " 2: dbf %%d0,1b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #5,%%d0\n" \ - " bra 4f\n" \ - " 3: move.l (%0)+,(%1)\n" \ - "31: move.l (%0)+,(%1)\n" \ - "32: move.l (%0)+,(%1)\n" \ - "33: move.l (%0)+,(%1)\n" \ - "34: move.l (%0)+,(%1)\n" \ - "35: move.l (%0)+,(%1)\n" \ - "36: move.l (%0)+,(%1)\n" \ - "37: move.l (%0)+,(%1)\n" \ - " 4: dbf %%d0,3b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #2,%%d0\n" \ - " and.w #7,%%d0\n" \ - " bra 6f\n" \ - " 5: move.l (%0)+,(%1)\n" \ - " 6: dbf %%d0,5b\n" \ - " and.w #3,%2\n" \ - " bra 8f\n" \ - " 7: move.b (%0)+,(%1)\n" \ - " 8: dbf %2,7b\n" \ - " moveq.l #0, %2\n" \ - " 9: \n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "91: moveq.l #1, %2\n" \ - " jra 9b\n" \ - "94: moveq.l #4, %2\n" \ - " jra 9b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,91b\n" \ - " .long 3b,94b\n" \ - " .long 31b,94b\n" \ - " .long 32b,94b\n" \ - " .long 33b,94b\n" \ - " .long 34b,94b\n" \ - " .long 35b,94b\n" \ - " .long 36b,94b\n" \ - " .long 37b,94b\n" \ - " .long 5b,94b\n" \ - " .long 7b,91b\n" \ - ".previous" \ - : "=a"(s), "=a"(d), "=d"(n) \ - : "0"(s), "1"(d), "2"(n) \ - : "d0") - static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, unsigned char *src, int len) { unsigned char *s = src; u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); - int n = len; - int transferred; + int result = 0; + + hostdata->pdma_residual = len; while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_DRQ | BASR_PHASE_MATCH, BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { - CP_MEM_TO_IO(s, d, n); + int bytes; - transferred = s - src - n; - hostdata->pdma_residual = len - transferred; + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | + CTRL_INTERRUPTS_ENABLE); - /* Target changed phase early? */ - if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, - BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0) - scmd_printk(KERN_ERR, hostdata->connected, - "%s: !REQ and !ACK\n", __func__); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) - return 0; + bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512)); + + if (bytes > 0) { + s += bytes; + hostdata->pdma_residual -= bytes; + } - /* No bus error. */ - if (n == 0) { + if (hostdata->pdma_residual == 0) { if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG, TCR_LAST_BYTE_SENT, - TCR_LAST_BYTE_SENT, HZ / 64) < 0) + TCR_LAST_BYTE_SENT, + HZ / 64) < 0) { scmd_printk(KERN_ERR, hostdata->connected, "%s: Last Byte Sent timeout\n", __func__); - return 0; + result = -1; + } + goto out; } + if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, + BUS_AND_STATUS_REG, BASR_ACK, + BASR_ACK, HZ / 64) < 0) + scmd_printk(KERN_DEBUG, hostdata->connected, + "%s: !REQ and !ACK\n", __func__); + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) + goto out; + + if (bytes == 0) + udelay(MAC_PDMA_DELAY); + + if (bytes >= 0) + continue; + dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, - "%s: bus error (%d/%d)\n", __func__, transferred, len); + "%s: bus error (%d/%d)\n", __func__, s - src, len); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - s = src + transferred; - n = len - transferred; + result = -1; + goto out; } scmd_printk(KERN_ERR, hostdata->connected, "%s: phase mismatch or !DRQ\n", __func__); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - - return -1; + result = -1; +out: + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); + return result; } static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, struct scsi_cmnd *cmd) { if (hostdata->flags & FLAG_NO_PSEUDO_DMA || - cmd->SCp.this_residual < 16) + cmd->SCp.this_residual < setup_use_pdma) return 0; return cmd->SCp.this_residual; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 4862f65ec3e8..45a66048801b 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * * Linux MegaRAID device driver * * Copyright (c) 2002 LSI Logic Corporation. * - * 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. - * * Copyright (c) 2002 Red Hat, Inc. All rights reserved. * - fixes * - speed-ups (list handling fixes, issued_list, optimizations.) @@ -28,7 +24,6 @@ * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, * and others. Please send updates to the mailing list * linux-scsi@vger.kernel.org . - * */ #include <linux/mm.h> diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid index 17419e30ffc8..2adc2afd9f91 100644 --- a/drivers/scsi/megaraid/Kconfig.megaraid +++ b/drivers/scsi/megaraid/Kconfig.megaraid @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config MEGARAID_NEWGEN bool "LSI Logic New Generation RAID Device Drivers" depends on PCI && SCSI @@ -78,6 +79,7 @@ config MEGARAID_LEGACY config MEGARAID_SAS tristate "LSI Logic MegaRAID SAS RAID Module" depends on PCI && SCSI + select IRQ_POLL help Module for LSI Logic's SAS based RAID controllers. To compile this driver as a module, choose 'm' here. diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile index 6e74d21227a5..12177e4cae65 100644 --- a/drivers/scsi/megaraid/Makefile +++ b/drivers/scsi/megaraid/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \ - megaraid_sas_fp.o + megaraid_sas_fp.o megaraid_sas_debugfs.o diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h index e01c6f7c2cac..01a1bfb8ea2a 100644 --- a/drivers/scsi/megaraid/mbox_defs.h +++ b/drivers/scsi/megaraid/mbox_defs.h @@ -1,16 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * * Linux MegaRAID Unified device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : mbox_defs.h - * */ #ifndef _MRAID_MBOX_DEFS_H_ #define _MRAID_MBOX_DEFS_H_ diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index 1d037ed52c33..3a7596e47a88 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * * Linux MegaRAID device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : mega_common.h * * Libaray of common routine used by all low-level megaraid drivers diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h index eedcbde46459..ae9c2ff7edac 100644 --- a/drivers/scsi/megaraid/megaraid_ioctl.h +++ b/drivers/scsi/megaraid/megaraid_ioctl.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * * Linux MegaRAID device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : megaraid_ioctl.h * * Definitions to interface with user level applications diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index f112458023ff..f6ac819e6e96 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * * Linux MegaRAID device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : megaraid_mbox.c * Version : v2.20.5.1 (Nov 16 2006) * @@ -38,7 +34,6 @@ * Dell PERC 4e/DC 1000 0408 1028 0002 * Dell PERC 4e/SC 1000 0408 1028 0001 * - * * LSI MegaRAID SCSI 320-0 1000 1960 1000 A520 * LSI MegaRAID SCSI 320-1 1000 1960 1000 0520 * LSI MegaRAID SCSI 320-2 1000 1960 1000 0518 diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index e075aeb4012f..3e4347c6dab1 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * * Linux MegaRAID device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : megaraid_mbox.h */ diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 3ce837e4b24c..59cca898f088 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * * Linux MegaRAID device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : megaraid_mm.c * Version : v2.20.2.7 (Jul 16 2006) * diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h index a30e725f2d5c..bf4011590020 100644 --- a/drivers/scsi/megaraid/megaraid_mm.h +++ b/drivers/scsi/megaraid/megaraid_mm.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * * Linux MegaRAID device driver * * Copyright (c) 2003-2004 LSI Logic Corporation. * - * 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. - * * FILE : megaraid_mm.h */ diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 6fd57f7f0b1e..ca724fe91b8d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Linux MegaRAID driver for SAS based RAID controllers * @@ -5,19 +6,6 @@ * Copyright (c) 2013-2016 Avago Technologies * Copyright (c) 2016-2018 Broadcom Inc. * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - * * FILE: megaraid_sas.h * * Authors: Broadcom Inc. @@ -33,8 +21,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "07.707.51.00-rc1" -#define MEGASAS_RELDATE "February 7, 2019" +#define MEGASAS_VERSION "07.710.06.00-rc1" +#define MEGASAS_RELDATE "June 18, 2019" /* * Device IDs @@ -64,6 +52,10 @@ #define PCI_DEVICE_ID_LSI_AERO_10E2 0x10e2 #define PCI_DEVICE_ID_LSI_AERO_10E5 0x10e5 #define PCI_DEVICE_ID_LSI_AERO_10E6 0x10e6 +#define PCI_DEVICE_ID_LSI_AERO_10E0 0x10e0 +#define PCI_DEVICE_ID_LSI_AERO_10E3 0x10e3 +#define PCI_DEVICE_ID_LSI_AERO_10E4 0x10e4 +#define PCI_DEVICE_ID_LSI_AERO_10E7 0x10e7 /* * Intel HBA SSDIDs @@ -135,6 +127,8 @@ #define MFI_RESET_ADAPTER 0x00000002 #define MEGAMFI_FRAME_SIZE 64 +#define MFI_STATE_FAULT_CODE 0x0FFF0000 +#define MFI_STATE_FAULT_SUBCODE 0x0000FF00 /* * During FW init, clear pending cmds & reset state using inbound_msg_0 * @@ -202,6 +196,7 @@ enum MFI_CMD_OP { MFI_CMD_SMP = 0x7, MFI_CMD_STP = 0x8, MFI_CMD_NVME = 0x9, + MFI_CMD_TOOLBOX = 0xa, MFI_CMD_OP_COUNT, MFI_CMD_INVALID = 0xff }; @@ -1461,7 +1456,39 @@ struct megasas_ctrl_info { u8 reserved6[64]; - u32 rsvdForAdptOp[64]; + struct { + #if defined(__BIG_ENDIAN_BITFIELD) + u32 reserved:19; + u32 support_pci_lane_margining: 1; + u32 support_psoc_update:1; + u32 support_force_personality_change:1; + u32 support_fde_type_mix:1; + u32 support_snap_dump:1; + u32 support_nvme_tm:1; + u32 support_oce_only:1; + u32 support_ext_mfg_vpd:1; + u32 support_pcie:1; + u32 support_cvhealth_info:1; + u32 support_profile_change:2; + u32 mr_config_ext2_supported:1; + #else + u32 mr_config_ext2_supported:1; + u32 support_profile_change:2; + u32 support_cvhealth_info:1; + u32 support_pcie:1; + u32 support_ext_mfg_vpd:1; + u32 support_oce_only:1; + u32 support_nvme_tm:1; + u32 support_snap_dump:1; + u32 support_fde_type_mix:1; + u32 support_force_personality_change:1; + u32 support_psoc_update:1; + u32 support_pci_lane_margining: 1; + u32 reserved:19; + #endif + } adapter_operations5; + + u32 rsvdForAdptOp[63]; u8 reserved7[3]; @@ -1495,7 +1522,9 @@ struct megasas_ctrl_info { #define MEGASAS_FW_BUSY 1 /* Driver's internal Logging levels*/ -#define OCR_LOGS (1 << 0) +#define OCR_DEBUG (1 << 0) +#define TM_DEBUG (1 << 1) +#define LD_PD_DEBUG (1 << 2) #define SCAN_PD_CHANNEL 0x1 #define SCAN_VD_CHANNEL 0x2 @@ -1571,6 +1600,7 @@ enum FW_BOOT_CONTEXT { #define MFI_IO_TIMEOUT_SECS 180 #define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ) #define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30) +#define MEGASAS_SRIOV_MAX_RESET_TRIES_VF 1 #define MEGASAS_ROUTINE_WAIT_TIME_VF 300 #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001 @@ -1595,7 +1625,10 @@ enum FW_BOOT_CONTEXT { #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000 +#define MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET (1 << 24) + #define MR_CAN_HANDLE_64_BIT_DMA_OFFSET (1 << 25) +#define MR_INTR_COALESCING_SUPPORT_OFFSET (1 << 26) #define MEGASAS_WATCHDOG_THREAD_INTERVAL 1000 #define MEGASAS_WAIT_FOR_NEXT_DMA_MSECS 20 @@ -1774,7 +1807,7 @@ struct megasas_init_frame { __le32 pad_0; /*0Ch */ __le16 flags; /*10h */ - __le16 reserved_3; /*12h */ + __le16 replyqueue_mask; /*12h */ __le32 data_xfer_len; /*14h */ __le32 queue_info_new_phys_addr_lo; /*18h */ @@ -2172,6 +2205,10 @@ struct megasas_aen_event { struct megasas_irq_context { struct megasas_instance *instance; u32 MSIxIndex; + u32 os_irq; + struct irq_poll irqpoll; + bool irq_poll_scheduled; + bool irq_line_enable; }; struct MR_DRV_SYSTEM_INFO { @@ -2202,6 +2239,23 @@ enum MR_PD_TYPE { #define MR_DEFAULT_NVME_MDTS_KB 128 #define MR_NVME_PAGE_SIZE_MASK 0x000000FF +/*Aero performance parameters*/ +#define MR_HIGH_IOPS_QUEUE_COUNT 8 +#define MR_DEVICE_HIGH_IOPS_DEPTH 8 +#define MR_HIGH_IOPS_BATCH_COUNT 16 + +enum MR_PERF_MODE { + MR_BALANCED_PERF_MODE = 0, + MR_IOPS_PERF_MODE = 1, + MR_LATENCY_PERF_MODE = 2, +}; + +#define MEGASAS_PERF_MODE_2STR(mode) \ + ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \ + (mode) == MR_IOPS_PERF_MODE ? "IOPS" : \ + (mode) == MR_LATENCY_PERF_MODE ? "Latency" : \ + "Unknown") + struct megasas_instance { unsigned int *reply_map; @@ -2258,6 +2312,7 @@ struct megasas_instance { u32 secure_jbod_support; u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ bool use_seqnum_jbod_fp; /* Added for PD sequence */ + bool smp_affinity_enable; spinlock_t crashdump_lock; struct megasas_register_set __iomem *reg_set; @@ -2275,6 +2330,7 @@ struct megasas_instance { u16 ldio_threshold; u16 cur_can_queue; u32 max_sectors_per_req; + bool msix_load_balance; struct megasas_aen_event *ev; struct megasas_cmd **cmd_list; @@ -2302,15 +2358,13 @@ struct megasas_instance { struct pci_dev *pdev; u32 unique_id; u32 fw_support_ieee; + u32 threshold_reply_count; atomic_t fw_outstanding; atomic_t ldio_outstanding; atomic_t fw_reset_no_pci_access; - atomic_t ieee_sgl; - atomic_t prp_sgl; - atomic_t sge_holes_type1; - atomic_t sge_holes_type2; - atomic_t sge_holes_type3; + atomic64_t total_io_count; + atomic64_t high_iops_outstanding; struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; @@ -2378,8 +2432,18 @@ struct megasas_instance { u8 task_abort_tmo; u8 max_reset_tmo; u8 snapdump_wait_time; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *raidmap_dump; +#endif u8 enable_fw_dev_list; + bool atomic_desc_support; + bool support_seqnum_jbod_fp; + bool support_pci_lane_margining; + u8 low_latency_index_start; + int perf_mode; }; + struct MR_LD_VF_MAP { u32 size; union MR_LD_REF ref; @@ -2635,4 +2699,9 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance); void megasas_set_dma_settings(struct megasas_instance *instance, struct megasas_dcmd_frame *dcmd, dma_addr_t dma_addr, u32 dma_len); +int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, + bool do_adp_reset, + int ocr_context); +int megasas_irqpoll(struct irq_poll *irqpoll, int budget); +void megasas_dump_fusion_io(struct scsi_cmnd *scmd); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 293f5cf524d7..80ab9700f1de 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Linux MegaRAID driver for SAS based RAID controllers * @@ -5,19 +6,6 @@ * Copyright (c) 2013-2016 Avago Technologies * Copyright (c) 2016-2018 Broadcom Inc. * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - * * Authors: Broadcom Inc. * Sreenivas Bagalkote * Sumant Patro @@ -48,12 +36,14 @@ #include <linux/mutex.h> #include <linux/poll.h> #include <linux/vmalloc.h> +#include <linux/irq_poll.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/scsi_dbg.h> #include "megaraid_sas_fusion.h" #include "megaraid_sas.h" @@ -62,47 +52,59 @@ * Will be set in megasas_init_mfi if user does not provide */ static unsigned int max_sectors; -module_param_named(max_sectors, max_sectors, int, 0); +module_param_named(max_sectors, max_sectors, int, 0444); MODULE_PARM_DESC(max_sectors, "Maximum number of sectors per IO command"); static int msix_disable; -module_param(msix_disable, int, S_IRUGO); +module_param(msix_disable, int, 0444); MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0"); static unsigned int msix_vectors; -module_param(msix_vectors, int, S_IRUGO); +module_param(msix_vectors, int, 0444); MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW"); static int allow_vf_ioctls; -module_param(allow_vf_ioctls, int, S_IRUGO); +module_param(allow_vf_ioctls, int, 0444); MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0"); static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; -module_param(throttlequeuedepth, int, S_IRUGO); +module_param(throttlequeuedepth, int, 0444); MODULE_PARM_DESC(throttlequeuedepth, "Adapter queue depth when throttled due to I/O timeout. Default: 16"); unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME; -module_param(resetwaittime, int, S_IRUGO); +module_param(resetwaittime, int, 0444); MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s"); int smp_affinity_enable = 1; -module_param(smp_affinity_enable, int, S_IRUGO); +module_param(smp_affinity_enable, int, 0444); MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)"); int rdpq_enable = 1; -module_param(rdpq_enable, int, S_IRUGO); +module_param(rdpq_enable, int, 0444); MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)"); unsigned int dual_qdepth_disable; -module_param(dual_qdepth_disable, int, S_IRUGO); +module_param(dual_qdepth_disable, int, 0444); MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0"); unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; -module_param(scmd_timeout, int, S_IRUGO); +module_param(scmd_timeout, int, 0444); MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer."); +int perf_mode = -1; +module_param(perf_mode, int, 0444); +MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t" + "0 - balanced: High iops and low latency queues are allocated &\n\t\t" + "interrupt coalescing is enabled only on high iops queues\n\t\t" + "1 - iops: High iops queues are not allocated &\n\t\t" + "interrupt coalescing is enabled on all queues\n\t\t" + "2 - latency: High iops queues are not allocated &\n\t\t" + "interrupt coalescing is disabled on all queues\n\t\t" + "default mode is 'balanced'" + ); + MODULE_LICENSE("GPL"); MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com"); @@ -166,6 +168,10 @@ static struct pci_device_id megasas_pci_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)}, {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)}, {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)}, {} }; @@ -182,10 +188,17 @@ static u32 support_poll_for_event; u32 megasas_dbg_lvl; static u32 support_device_change; static bool support_nvme_encapsulation; +static bool support_pci_lane_margining; /* define lock for aen poll */ spinlock_t poll_aen_lock; +extern struct dentry *megasas_debugfs_root; +extern void megasas_init_debugfs(void); +extern void megasas_exit_debugfs(void); +extern void megasas_setup_debugfs(struct megasas_instance *instance); +extern void megasas_destroy_debugfs(struct megasas_instance *instance); + void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status); @@ -815,7 +828,6 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance, &(regs)->inbound_high_queue_port); writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1, &(regs)->inbound_low_queue_port); - mmiowb(); spin_unlock_irqrestore(&instance->hba_lock, flags); } @@ -1111,8 +1123,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, ret = wait_event_timeout(instance->int_cmd_wait_q, cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ); if (!ret) { - dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n", - __func__, __LINE__); + dev_err(&instance->pdev->dev, + "DCMD(opcode: 0x%x) is timed out, func:%s\n", + cmd->frame->dcmd.opcode, __func__); return DCMD_TIMEOUT; } } else @@ -1141,6 +1154,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd; struct megasas_abort_frame *abort_fr; int ret = 0; + u32 opcode; cmd = megasas_get_cmd(instance); @@ -1176,8 +1190,10 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, ret = wait_event_timeout(instance->abort_cmd_wait_q, cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ); if (!ret) { - dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n", - __func__, __LINE__); + opcode = cmd_to_abort->frame->dcmd.opcode; + dev_err(&instance->pdev->dev, + "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n", + opcode, __func__); return DCMD_TIMEOUT; } } else @@ -1931,7 +1947,6 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size) static void megasas_set_static_target_properties(struct scsi_device *sdev, bool is_target_prop) { - u16 target_index = 0; u8 interface_type; u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN; u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB; @@ -1948,8 +1963,6 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev, */ blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ); - target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id; - switch (interface_type) { case SAS_PD: device_qd = MEGASAS_SAS_QD; @@ -2725,7 +2738,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) do { if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) { dev_info(&instance->pdev->dev, - "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, oustanding 0x%x\n", + "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, outstanding 0x%x\n", __func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding)); if (i == 3) goto kill_hba_and_failed; @@ -2835,21 +2848,108 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) } /** - * megasas_dump_frame - This function will dump MPT/MFI frame + * megasas_dump - This function will print hexdump of provided buffer. + * @buf: Buffer to be dumped + * @sz: Size in bytes + * @format: Different formats of dumping e.g. format=n will + * cause only 'n' 32 bit words to be dumped in a single + * line. */ -static inline void -megasas_dump_frame(void *mpi_request, int sz) +inline void +megasas_dump(void *buf, int sz, int format) { int i; - __le32 *mfp = (__le32 *)mpi_request; + __le32 *buf_loc = (__le32 *)buf; + + for (i = 0; i < (sz / sizeof(__le32)); i++) { + if ((i % format) == 0) { + if (i != 0) + printk(KERN_CONT "\n"); + printk(KERN_CONT "%08x: ", (i * 4)); + } + printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i])); + } + printk(KERN_CONT "\n"); +} + +/** + * megasas_dump_reg_set - This function will print hexdump of register set + * @buf: Buffer to be dumped + * @sz: Size in bytes + * @format: Different formats of dumping e.g. format=n will + * cause only 'n' 32 bit words to be dumped in a + * single line. + */ +inline void +megasas_dump_reg_set(void __iomem *reg_set) +{ + unsigned int i, sz = 256; + u32 __iomem *reg = (u32 __iomem *)reg_set; + + for (i = 0; i < (sz / sizeof(u32)); i++) + printk("%08x: %08x\n", (i * 4), readl(®[i])); +} + +/** + * megasas_dump_fusion_io - This function will print key details + * of SCSI IO + * @scmd: SCSI command pointer of SCSI IO + */ +void +megasas_dump_fusion_io(struct scsi_cmnd *scmd) +{ + struct megasas_cmd_fusion *cmd; + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; + struct megasas_instance *instance; + + cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr; + instance = (struct megasas_instance *)scmd->device->host->hostdata; + + scmd_printk(KERN_INFO, scmd, + "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n", + scmd, scmd->retries, scmd->allowed); + scsi_print_command(scmd); - printk(KERN_INFO "IO request frame:\n\t"); - for (i = 0; i < sz / sizeof(__le32); i++) { - if (i && ((i % 8) == 0)) - printk("\n\t"); - printk("%08x ", le32_to_cpu(mfp[i])); + if (cmd) { + req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; + scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n"); + scmd_printk(KERN_INFO, scmd, + "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n", + req_desc->SCSIIO.RequestFlags, + req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID, + req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle); + + printk(KERN_INFO "IO request frame:\n"); + megasas_dump(cmd->io_request, + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8); + printk(KERN_INFO "Chain frame:\n"); + megasas_dump(cmd->sg_frame, + instance->max_chain_frame_sz, 8); + } + +} + +/* + * megasas_dump_sys_regs - This function will dump system registers through + * sysfs. + * @reg_set: Pointer to System register set. + * @buf: Buffer to which output is to be written. + * @return: Number of bytes written to buffer. + */ +static inline ssize_t +megasas_dump_sys_regs(void __iomem *reg_set, char *buf) +{ + unsigned int i, sz = 256; + int bytes_wrote = 0; + char *loc = (char *)buf; + u32 __iomem *reg = (u32 __iomem *)reg_set; + + for (i = 0; i < sz / sizeof(u32); i++) { + bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE, + "%08x: %08x\n", (i * 4), + readl(®[i])); } - printk("\n"); + return bytes_wrote; } /** @@ -2863,24 +2963,20 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; scmd_printk(KERN_INFO, scmd, - "Controller reset is requested due to IO timeout\n" - "SCSI command pointer: (%p)\t SCSI host state: %d\t" - " SCSI host busy: %d\t FW outstanding: %d\n", - scmd, scmd->device->host->shost_state, + "OCR is requested due to IO timeout!!\n"); + + scmd_printk(KERN_INFO, scmd, + "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n", + scmd->device->host->shost_state, scsi_host_busy(scmd->device->host), atomic_read(&instance->fw_outstanding)); - /* * First wait for all commands to complete */ if (instance->adapter_type == MFI_SERIES) { ret = megasas_generic_reset(scmd); } else { - struct megasas_cmd_fusion *cmd; - cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr; - if (cmd) - megasas_dump_frame(cmd->io_request, - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE); + megasas_dump_fusion_io(scmd); ret = megasas_reset_fusion(scmd->device->host, SCSIIO_TIMEOUT_OCR); } @@ -3030,7 +3126,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) } static ssize_t -megasas_fw_crash_buffer_store(struct device *cdev, +fw_crash_buffer_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3049,14 +3145,13 @@ megasas_fw_crash_buffer_store(struct device *cdev, } static ssize_t -megasas_fw_crash_buffer_show(struct device *cdev, +fw_crash_buffer_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; u32 size; - unsigned long buff_addr; unsigned long dmachunk = CRASH_DMA_BUF_SIZE; unsigned long src_addr; unsigned long flags; @@ -3073,8 +3168,6 @@ megasas_fw_crash_buffer_show(struct device *cdev, return -EINVAL; } - buff_addr = (unsigned long) buf; - if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) { dev_err(&instance->pdev->dev, "Firmware crash dump offset is out of range\n"); @@ -3094,7 +3187,7 @@ megasas_fw_crash_buffer_show(struct device *cdev, } static ssize_t -megasas_fw_crash_buffer_size_show(struct device *cdev, +fw_crash_buffer_size_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3106,7 +3199,7 @@ megasas_fw_crash_buffer_size_show(struct device *cdev, } static ssize_t -megasas_fw_crash_state_store(struct device *cdev, +fw_crash_state_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3141,7 +3234,7 @@ megasas_fw_crash_state_store(struct device *cdev, } static ssize_t -megasas_fw_crash_state_show(struct device *cdev, +fw_crash_state_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3152,14 +3245,14 @@ megasas_fw_crash_state_show(struct device *cdev, } static ssize_t -megasas_page_size_show(struct device *cdev, +page_size_show(struct device *cdev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1); } static ssize_t -megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr, +ldio_outstanding_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3169,7 +3262,7 @@ megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr } static ssize_t -megasas_fw_cmds_outstanding_show(struct device *cdev, +fw_cmds_outstanding_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3178,18 +3271,37 @@ megasas_fw_cmds_outstanding_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding)); } -static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR, - megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store); -static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, - megasas_fw_crash_buffer_size_show, NULL); -static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR, - megasas_fw_crash_state_show, megasas_fw_crash_state_store); -static DEVICE_ATTR(page_size, S_IRUGO, - megasas_page_size_show, NULL); -static DEVICE_ATTR(ldio_outstanding, S_IRUGO, - megasas_ldio_outstanding_show, NULL); -static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO, - megasas_fw_cmds_outstanding_show, NULL); +static ssize_t +dump_system_regs_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct megasas_instance *instance = + (struct megasas_instance *)shost->hostdata; + + return megasas_dump_sys_regs(instance->reg_set, buf); +} + +static ssize_t +raid_map_id_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct megasas_instance *instance = + (struct megasas_instance *)shost->hostdata; + + return snprintf(buf, PAGE_SIZE, "%ld\n", + (unsigned long)instance->map_id); +} + +static DEVICE_ATTR_RW(fw_crash_buffer); +static DEVICE_ATTR_RO(fw_crash_buffer_size); +static DEVICE_ATTR_RW(fw_crash_state); +static DEVICE_ATTR_RO(page_size); +static DEVICE_ATTR_RO(ldio_outstanding); +static DEVICE_ATTR_RO(fw_cmds_outstanding); +static DEVICE_ATTR_RO(dump_system_regs); +static DEVICE_ATTR_RO(raid_map_id); struct device_attribute *megaraid_host_attrs[] = { &dev_attr_fw_crash_buffer_size, @@ -3198,6 +3310,8 @@ struct device_attribute *megaraid_host_attrs[] = { &dev_attr_page_size, &dev_attr_ldio_outstanding, &dev_attr_fw_cmds_outstanding, + &dev_attr_dump_system_regs, + &dev_attr_raid_map_id, NULL, }; @@ -3381,6 +3495,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, case MFI_CMD_SMP: case MFI_CMD_STP: case MFI_CMD_NVME: + case MFI_CMD_TOOLBOX: megasas_complete_int_cmd(instance, cmd); break; @@ -3789,7 +3904,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) int i; u8 max_wait; u32 fw_state; - u32 cur_state; u32 abs_state, curr_abs_state; abs_state = instance->instancet->read_fw_status_reg(instance); @@ -3804,13 +3918,18 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) switch (fw_state) { case MFI_STATE_FAULT: - dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW in FAULT state!!\n"); + dev_printk(KERN_ERR, &instance->pdev->dev, + "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n", + abs_state & MFI_STATE_FAULT_CODE, + abs_state & MFI_STATE_FAULT_SUBCODE, __func__); if (ocr) { max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FAULT; break; - } else + } else { + dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); + megasas_dump_reg_set(instance->reg_set); return -ENODEV; + } case MFI_STATE_WAIT_HANDSHAKE: /* @@ -3830,7 +3949,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) &instance->reg_set->inbound_doorbell); max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_WAIT_HANDSHAKE; break; case MFI_STATE_BOOT_MESSAGE_PENDING: @@ -3846,7 +3964,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) &instance->reg_set->inbound_doorbell); max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_BOOT_MESSAGE_PENDING; break; case MFI_STATE_OPERATIONAL: @@ -3879,7 +3996,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) &instance->reg_set->inbound_doorbell); max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_OPERATIONAL; break; case MFI_STATE_UNDEFINED: @@ -3887,37 +4003,33 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) * This state should not last for more than 2 seconds */ max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_UNDEFINED; break; case MFI_STATE_BB_INIT: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_BB_INIT; break; case MFI_STATE_FW_INIT: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FW_INIT; break; case MFI_STATE_FW_INIT_2: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FW_INIT_2; break; case MFI_STATE_DEVICE_SCAN: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_DEVICE_SCAN; break; case MFI_STATE_FLUSH_CACHE: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FLUSH_CACHE; break; default: dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n", fw_state); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); + megasas_dump_reg_set(instance->reg_set); return -ENODEV; } @@ -3940,6 +4052,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) if (curr_abs_state == abs_state) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed " "in %d secs\n", fw_state, max_wait); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); + megasas_dump_reg_set(instance->reg_set); return -ENODEV; } @@ -4003,23 +4117,12 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) { int i; u16 max_cmd; - u32 sge_sz; u32 frame_count; struct megasas_cmd *cmd; max_cmd = instance->max_mfi_cmds; /* - * Size of our frame is 64 bytes for MFI frame, followed by max SG - * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer - */ - sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : - sizeof(struct megasas_sge32); - - if (instance->flag_ieee) - sge_sz = sizeof(struct megasas_sge_skinny); - - /* * For MFI controllers. * max_num_sge = 60 * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) @@ -4268,8 +4371,10 @@ megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev) switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -4305,7 +4410,6 @@ megasas_get_pd_list(struct megasas_instance *instance) struct megasas_dcmd_frame *dcmd; struct MR_PD_LIST *ci; struct MR_PD_ADDRESS *pd_addr; - dma_addr_t ci_h = 0; if (instance->pd_list_not_supported) { dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " @@ -4314,7 +4418,6 @@ megasas_get_pd_list(struct megasas_instance *instance) } ci = instance->pd_list_buf; - ci_h = instance->pd_list_buf_h; cmd = megasas_get_cmd(instance); @@ -4387,6 +4490,9 @@ megasas_get_pd_list(struct megasas_instance *instance) case DCMD_SUCCESS: pd_addr = ci->addr; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n", + __func__, le32_to_cpu(ci->count)); if ((le32_to_cpu(ci->count) > (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) @@ -4402,6 +4508,11 @@ megasas_get_pd_list(struct megasas_instance *instance) pd_addr->scsiDevType; instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState = MR_PD_STATE_SYSTEM; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "PD%d: targetID: 0x%03x deviceType:0x%x\n", + pd_index, le16_to_cpu(pd_addr->deviceId), + pd_addr->scsiDevType); pd_addr++; } @@ -4505,6 +4616,10 @@ megasas_get_ld_list(struct megasas_instance *instance) break; case DCMD_SUCCESS: + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n", + __func__, ld_count); + if (ld_count > instance->fw_supported_vd_count) break; @@ -4514,6 +4629,10 @@ megasas_get_ld_list(struct megasas_instance *instance) if (ci->ldList[ld_index].state != 0) { ids = ci->ldList[ld_index].ref.targetId; instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "LD%d: targetID: 0x%03x\n", + ld_index, ids); } } @@ -4617,6 +4736,10 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) case DCMD_SUCCESS: tgtid_count = le32_to_cpu(ci->count); + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n", + __func__, tgtid_count); + if ((tgtid_count > (instance->fw_supported_vd_count))) break; @@ -4624,6 +4747,9 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) for (ld_index = 0; ld_index < tgtid_count; ld_index++) { ids = ci->targetId[ld_index]; instance->ld_ids[ids] = ci->targetId[ld_index]; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n", + ld_index, ci->targetId[ld_index]); } break; @@ -4648,7 +4774,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) * Return: 0 if DCMD succeeded * non-zero if failed */ -int +static int megasas_host_device_list_query(struct megasas_instance *instance, bool is_probe) { @@ -4703,6 +4829,13 @@ megasas_host_device_list_query(struct megasas_instance *instance, */ count = le32_to_cpu(ci->count); + if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT)) + break; + + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n", + __func__, count); + memset(instance->local_pd_list, 0, MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)); memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT); @@ -4714,8 +4847,16 @@ megasas_host_device_list_query(struct megasas_instance *instance, ci->host_device_list[i].scsi_type; instance->local_pd_list[target_id].driveState = MR_PD_STATE_SYSTEM; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "Device %d: PD targetID: 0x%03x deviceType:0x%x\n", + i, target_id, ci->host_device_list[i].scsi_type); } else { instance->ld_ids[target_id] = target_id; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "Device %d: LD targetID: 0x%03x\n", + i, target_id); } } @@ -4727,8 +4868,10 @@ megasas_host_device_list_query(struct megasas_instance *instance, switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -4876,8 +5019,10 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance) switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -4956,6 +5101,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance) le32_to_cpus((u32 *)&ci->adapterOperations2); le32_to_cpus((u32 *)&ci->adapterOperations3); le16_to_cpus((u16 *)&ci->adapter_operations4); + le32_to_cpus((u32 *)&ci->adapter_operations5); /* Update the latest Ext VD info. * From Init path, store current firmware details. @@ -4963,12 +5109,14 @@ megasas_get_ctrl_info(struct megasas_instance *instance) * in case of Firmware upgrade without system reboot. */ megasas_update_ext_vd_details(instance); - instance->use_seqnum_jbod_fp = + instance->support_seqnum_jbod_fp = ci->adapterOperations3.useSeqNumJbodFP; instance->support_morethan256jbod = ci->adapter_operations4.support_pd_map_target_id; instance->support_nvme_passthru = ci->adapter_operations4.support_nvme_passthru; + instance->support_pci_lane_margining = + ci->adapter_operations5.support_pci_lane_margining; instance->task_abort_tmo = ci->TaskAbortTO; instance->max_reset_tmo = ci->MaxResetTO; @@ -5000,6 +5148,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance) dev_info(&instance->pdev->dev, "FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n", instance->task_abort_tmo, instance->max_reset_tmo); + dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n", + instance->support_seqnum_jbod_fp ? "Yes" : "No"); + dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n", + instance->support_pci_lane_margining ? "Yes" : "No"); break; @@ -5007,8 +5159,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance) switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -5275,6 +5429,25 @@ fail_alloc_cmds: return 1; } +static +void megasas_setup_irq_poll(struct megasas_instance *instance) +{ + struct megasas_irq_context *irq_ctx; + u32 count, i; + + count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + + /* Initialize IRQ poll */ + for (i = 0; i < count; i++) { + irq_ctx = &instance->irq_context[i]; + irq_ctx->os_irq = pci_irq_vector(instance->pdev, i); + irq_ctx->irq_poll_scheduled = false; + irq_poll_init(&irq_ctx->irqpoll, + instance->threshold_reply_count, + megasas_irqpoll); + } +} + /* * megasas_setup_irqs_ioapic - register legacy interrupts. * @instance: Adapter soft state @@ -5299,6 +5472,8 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance) __func__, __LINE__); return -1; } + instance->perf_mode = MR_LATENCY_PERF_MODE; + instance->low_latency_index_start = 0; return 0; } @@ -5333,6 +5508,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) &instance->irq_context[j]); /* Retry irq register for IO_APIC*/ instance->msix_vectors = 0; + instance->msix_load_balance = false; if (is_probe) { pci_free_irq_vectors(instance->pdev); return megasas_setup_irqs_ioapic(instance); @@ -5341,6 +5517,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) } } } + return 0; } @@ -5353,6 +5530,16 @@ static void megasas_destroy_irqs(struct megasas_instance *instance) { int i; + int count; + struct megasas_irq_context *irq_ctx; + + count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + if (instance->adapter_type != MFI_SERIES) { + for (i = 0; i < count; i++) { + irq_ctx = &instance->irq_context[i]; + irq_poll_disable(&irq_ctx->irqpoll); + } + } if (instance->msix_vectors) for (i = 0; i < instance->msix_vectors; i++) { @@ -5381,10 +5568,12 @@ megasas_setup_jbod_map(struct megasas_instance *instance) pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1)); + instance->use_seqnum_jbod_fp = + instance->support_seqnum_jbod_fp; if (reset_devices || !fusion || - !instance->ctrl_info_buf->adapterOperations3.useSeqNumJbodFP) { + !instance->support_seqnum_jbod_fp) { dev_info(&instance->pdev->dev, - "Jbod map is not supported %s %d\n", + "JBOD sequence map is disabled %s %d\n", __func__, __LINE__); instance->use_seqnum_jbod_fp = false; return; @@ -5423,9 +5612,11 @@ skip_alloc: static void megasas_setup_reply_map(struct megasas_instance *instance) { const struct cpumask *mask; - unsigned int queue, cpu; + unsigned int queue, cpu, low_latency_index_start; - for (queue = 0; queue < instance->msix_vectors; queue++) { + low_latency_index_start = instance->low_latency_index_start; + + for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) { mask = pci_irq_get_affinity(instance->pdev, queue); if (!mask) goto fallback; @@ -5436,8 +5627,14 @@ static void megasas_setup_reply_map(struct megasas_instance *instance) return; fallback: - for_each_possible_cpu(cpu) - instance->reply_map[cpu] = cpu % instance->msix_vectors; + queue = low_latency_index_start; + for_each_possible_cpu(cpu) { + instance->reply_map[cpu] = queue; + if (queue == (instance->msix_vectors - 1)) + queue = low_latency_index_start; + else + queue++; + } } /** @@ -5474,6 +5671,89 @@ int megasas_get_device_list(struct megasas_instance *instance) return SUCCESS; } + +/** + * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues + * @instance: Adapter soft state + * return: void + */ +static inline void +megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance) +{ + int i; + int local_numa_node; + + if (instance->perf_mode == MR_BALANCED_PERF_MODE) { + local_numa_node = dev_to_node(&instance->pdev->dev); + + for (i = 0; i < instance->low_latency_index_start; i++) + irq_set_affinity_hint(pci_irq_vector(instance->pdev, i), + cpumask_of_node(local_numa_node)); + } +} + +static int +__megasas_alloc_irq_vectors(struct megasas_instance *instance) +{ + int i, irq_flags; + struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start }; + struct irq_affinity *descp = &desc; + + irq_flags = PCI_IRQ_MSIX; + + if (instance->smp_affinity_enable) + irq_flags |= PCI_IRQ_AFFINITY; + else + descp = NULL; + + i = pci_alloc_irq_vectors_affinity(instance->pdev, + instance->low_latency_index_start, + instance->msix_vectors, irq_flags, descp); + + return i; +} + +/** + * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors + * @instance: Adapter soft state + * return: void + */ +static void +megasas_alloc_irq_vectors(struct megasas_instance *instance) +{ + int i; + unsigned int num_msix_req; + + i = __megasas_alloc_irq_vectors(instance); + + if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && + (i != instance->msix_vectors)) { + if (instance->msix_vectors) + pci_free_irq_vectors(instance->pdev); + /* Disable Balanced IOPS mode and try realloc vectors */ + instance->perf_mode = MR_LATENCY_PERF_MODE; + instance->low_latency_index_start = 1; + num_msix_req = num_online_cpus() + instance->low_latency_index_start; + + instance->msix_vectors = min(num_msix_req, + instance->msix_vectors); + + i = __megasas_alloc_irq_vectors(instance); + + } + + dev_info(&instance->pdev->dev, + "requested/available msix %d/%d\n", instance->msix_vectors, i); + + if (i > 0) + instance->msix_vectors = i; + else + instance->msix_vectors = 0; + + if (instance->smp_affinity_enable) + megasas_set_high_iops_queue_affinity_hint(instance); +} + /** * megasas_init_fw - Initializes the FW * @instance: Adapter soft state @@ -5487,12 +5767,15 @@ static int megasas_init_fw(struct megasas_instance *instance) u32 max_sectors_2, tmp_sectors, msix_enable; u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg; resource_size_t base_addr; + void *base_addr_phys; struct megasas_ctrl_info *ctrl_info = NULL; unsigned long bar_list; - int i, j, loop, fw_msix_count = 0; + int i, j, loop; struct IOV_111 *iovPtr; struct fusion_context *fusion; - bool do_adp_reset = true; + bool intr_coalescing; + unsigned int num_msix_req; + u16 lnksta, speed; fusion = instance->ctrl_context; @@ -5513,6 +5796,11 @@ static int megasas_init_fw(struct megasas_instance *instance) goto fail_ioremap; } + base_addr_phys = &base_addr; + dev_printk(KERN_DEBUG, &instance->pdev->dev, + "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n", + instance->bar, base_addr_phys, instance->reg_set); + if (instance->adapter_type != MFI_SERIES) instance->instancet = &megasas_instance_template_fusion; else { @@ -5539,29 +5827,35 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (megasas_transition_to_ready(instance, 0)) { - if (instance->adapter_type >= INVADER_SERIES) { + dev_info(&instance->pdev->dev, + "Failed to transition controller to ready from %s!\n", + __func__); + if (instance->adapter_type != MFI_SERIES) { status_reg = instance->instancet->read_fw_status_reg( instance); - do_adp_reset = status_reg & MFI_RESET_ADAPTER; - } - - if (do_adp_reset) { + if (status_reg & MFI_RESET_ADAPTER) { + if (megasas_adp_reset_wait_for_ready + (instance, true, 0) == FAILED) + goto fail_ready_state; + } else { + goto fail_ready_state; + } + } else { atomic_set(&instance->fw_reset_no_pci_access, 1); instance->instancet->adp_reset (instance, instance->reg_set); atomic_set(&instance->fw_reset_no_pci_access, 0); - dev_info(&instance->pdev->dev, - "FW restarted successfully from %s!\n", - __func__); /*waiting for about 30 second before retry*/ ssleep(30); if (megasas_transition_to_ready(instance, 0)) goto fail_ready_state; - } else { - goto fail_ready_state; } + + dev_info(&instance->pdev->dev, + "FW restarted successfully from %s!\n", + __func__); } megasas_init_ctrl_params(instance); @@ -5586,11 +5880,21 @@ static int megasas_init_fw(struct megasas_instance *instance) MR_MAX_RAID_MAP_SIZE_MASK); } + switch (instance->adapter_type) { + case VENTURA_SERIES: + fusion->pcie_bw_limitation = true; + break; + case AERO_SERIES: + fusion->r56_div_offload = true; + break; + default: + break; + } + /* Check if MSI-X is supported while in ready state */ msix_enable = (instance->instancet->read_fw_status_reg(instance) & 0x4000000) >> 0x1a; if (msix_enable && !msix_disable) { - int irq_flags = PCI_IRQ_MSIX; scratch_pad_1 = megasas_readl (instance, &instance->reg_set->outbound_scratch_pad_1); @@ -5600,7 +5904,6 @@ static int megasas_init_fw(struct megasas_instance *instance) /* Thunderbolt Series*/ instance->msix_vectors = (scratch_pad_1 & MR_MAX_REPLY_QUEUES_OFFSET) + 1; - fw_msix_count = instance->msix_vectors; } else { instance->msix_vectors = ((scratch_pad_1 & MR_MAX_REPLY_QUEUES_EXT_OFFSET) @@ -5629,7 +5932,12 @@ static int megasas_init_fw(struct megasas_instance *instance) if (rdpq_enable) instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; - fw_msix_count = instance->msix_vectors; + + if (!instance->msix_combined) { + instance->msix_load_balance = true; + instance->smp_affinity_enable = false; + } + /* Save 1-15 reply post index address to local memory * Index 0 is already saved from reg offset * MPI2_REPLY_POST_HOST_INDEX_OFFSET @@ -5642,22 +5950,91 @@ static int megasas_init_fw(struct megasas_instance *instance) + (loop * 0x10)); } } + + dev_info(&instance->pdev->dev, + "firmware supports msix\t: (%d)", + instance->msix_vectors); if (msix_vectors) instance->msix_vectors = min(msix_vectors, instance->msix_vectors); } else /* MFI adapters */ instance->msix_vectors = 1; - /* Don't bother allocating more MSI-X vectors than cpus */ - instance->msix_vectors = min(instance->msix_vectors, - (unsigned int)num_online_cpus()); - if (smp_affinity_enable) - irq_flags |= PCI_IRQ_AFFINITY; - i = pci_alloc_irq_vectors(instance->pdev, 1, - instance->msix_vectors, irq_flags); - if (i > 0) - instance->msix_vectors = i; + + + /* + * For Aero (if some conditions are met), driver will configure a + * few additional reply queues with interrupt coalescing enabled. + * These queues with interrupt coalescing enabled are called + * High IOPS queues and rest of reply queues (based on number of + * logical CPUs) are termed as Low latency queues. + * + * Total Number of reply queues = High IOPS queues + low latency queues + * + * For rest of fusion adapters, 1 additional reply queue will be + * reserved for management commands, rest of reply queues + * (based on number of logical CPUs) will be used for IOs and + * referenced as IO queues. + * Total Number of reply queues = 1 + IO queues + * + * MFI adapters supports single MSI-x so single reply queue + * will be used for IO and management commands. + */ + + intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? + true : false; + if (intr_coalescing && + (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) && + (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES)) + instance->perf_mode = MR_BALANCED_PERF_MODE; else - instance->msix_vectors = 0; + instance->perf_mode = MR_LATENCY_PERF_MODE; + + + if (instance->adapter_type == AERO_SERIES) { + pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta); + speed = lnksta & PCI_EXP_LNKSTA_CLS; + + /* + * For Aero, if PCIe link speed is <16 GT/s, then driver should operate + * in latency perf mode and enable R1 PCI bandwidth algorithm + */ + if (speed < 0x4) { + instance->perf_mode = MR_LATENCY_PERF_MODE; + fusion->pcie_bw_limitation = true; + } + + /* + * Performance mode settings provided through module parameter-perf_mode will + * take affect only for: + * 1. Aero family of adapters. + * 2. When user sets module parameter- perf_mode in range of 0-2. + */ + if ((perf_mode >= MR_BALANCED_PERF_MODE) && + (perf_mode <= MR_LATENCY_PERF_MODE)) + instance->perf_mode = perf_mode; + /* + * If intr coalescing is not supported by controller FW, then IOPS + * and Balanced modes are not feasible. + */ + if (!intr_coalescing) + instance->perf_mode = MR_LATENCY_PERF_MODE; + + } + + if (instance->perf_mode == MR_BALANCED_PERF_MODE) + instance->low_latency_index_start = + MR_HIGH_IOPS_QUEUE_COUNT; + else + instance->low_latency_index_start = 1; + + num_msix_req = num_online_cpus() + instance->low_latency_index_start; + + instance->msix_vectors = min(num_msix_req, + instance->msix_vectors); + + megasas_alloc_irq_vectors(instance); + if (!instance->msix_vectors) + instance->msix_load_balance = false; } /* * MSI-X host index 0 is common for all adapter. @@ -5682,8 +6059,6 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_reply_map(instance); dev_info(&instance->pdev->dev, - "firmware supports msix\t: (%d)", fw_msix_count); - dev_info(&instance->pdev->dev, "current msix/online cpus\t: (%d/%d)\n", instance->msix_vectors, (unsigned int)num_online_cpus()); dev_info(&instance->pdev->dev, @@ -5720,6 +6095,9 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_irqs_ioapic(instance)) goto fail_init_adapter; + if (instance->adapter_type != MFI_SERIES) + megasas_setup_irq_poll(instance); + instance->instancet->enable_intr(instance); dev_info(&instance->pdev->dev, "INIT adapter done\n"); @@ -5846,8 +6224,8 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->UnevenSpanSupport ? "yes" : "no"); dev_info(&instance->pdev->dev, "firmware crash dump : %s\n", instance->crash_dump_drv_support ? "yes" : "no"); - dev_info(&instance->pdev->dev, "jbod sync map : %s\n", - instance->use_seqnum_jbod_fp ? "yes" : "no"); + dev_info(&instance->pdev->dev, "JBOD sequence map : %s\n", + instance->use_seqnum_jbod_fp ? "enabled" : "disabled"); instance->max_sectors_per_req = instance->max_num_sge * SGE_BUFFER_SIZE / 512; @@ -6210,8 +6588,10 @@ megasas_get_target_prop(struct megasas_instance *instance, switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -6761,6 +7141,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) INIT_LIST_HEAD(&instance->internal_reset_pending_q); atomic_set(&instance->fw_outstanding, 0); + atomic64_set(&instance->total_io_count, 0); init_waitqueue_head(&instance->int_cmd_wait_q); init_waitqueue_head(&instance->abort_cmd_wait_q); @@ -6783,6 +7164,8 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) instance->last_time = 0; instance->disableOnlineCtrlReset = 1; instance->UnevenSpanSupport = 0; + instance->smp_affinity_enable = smp_affinity_enable ? true : false; + instance->msix_load_balance = false; if (instance->adapter_type != MFI_SERIES) INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); @@ -6804,6 +7187,12 @@ static int megasas_probe_one(struct pci_dev *pdev, u16 control = 0; switch (pdev->device) { + case PCI_DEVICE_ID_LSI_AERO_10E0: + case PCI_DEVICE_ID_LSI_AERO_10E3: + case PCI_DEVICE_ID_LSI_AERO_10E4: + case PCI_DEVICE_ID_LSI_AERO_10E7: + dev_err(&pdev->dev, "Adapter is in non secure mode\n"); + return 1; case PCI_DEVICE_ID_LSI_AERO_10E1: case PCI_DEVICE_ID_LSI_AERO_10E5: dev_info(&pdev->dev, "Adapter is in configurable secure mode\n"); @@ -6923,6 +7312,8 @@ static int megasas_probe_one(struct pci_dev *pdev, goto fail_start_aen; } + megasas_setup_debugfs(instance); + /* Get current SR-IOV LD/VF affiliation */ if (instance->requestorId) megasas_get_ld_vf_affiliation(instance, 1); @@ -7054,13 +7445,17 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, static int megasas_suspend(struct pci_dev *pdev, pm_message_t state) { - struct Scsi_Host *host; struct megasas_instance *instance; instance = pci_get_drvdata(pdev); - host = instance->host; + + if (!instance) + return 0; + instance->unload = 1; + dev_info(&pdev->dev, "%s is called\n", __func__); + /* Shutdown SR-IOV heartbeat timer */ if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); @@ -7110,11 +7505,16 @@ megasas_resume(struct pci_dev *pdev) int irq_flags = PCI_IRQ_LEGACY; instance = pci_get_drvdata(pdev); + + if (!instance) + return 0; + host = instance->host; pci_set_power_state(pdev, PCI_D0); pci_enable_wake(pdev, PCI_D0, 0); pci_restore_state(pdev); + dev_info(&pdev->dev, "%s is called\n", __func__); /* * PCI prepping: enable device set bus mastering and dma mask */ @@ -7146,7 +7546,7 @@ megasas_resume(struct pci_dev *pdev) /* Now re-enable MSI-X */ if (instance->msix_vectors) { irq_flags = PCI_IRQ_MSIX; - if (smp_affinity_enable) + if (instance->smp_affinity_enable) irq_flags |= PCI_IRQ_AFFINITY; } rval = pci_alloc_irq_vectors(instance->pdev, 1, @@ -7184,6 +7584,9 @@ megasas_resume(struct pci_dev *pdev) megasas_setup_irqs_ioapic(instance)) goto fail_init_mfi; + if (instance->adapter_type != MFI_SERIES) + megasas_setup_irq_poll(instance); + /* Re-launch SR-IOV heartbeat timer */ if (instance->requestorId) { if (!megasas_sriov_start_heartbeat(instance, 0)) @@ -7274,6 +7677,10 @@ static void megasas_detach_one(struct pci_dev *pdev) u32 pd_seq_map_sz; instance = pci_get_drvdata(pdev); + + if (!instance) + return; + host = instance->host; fusion = instance->ctrl_context; @@ -7387,6 +7794,8 @@ skip_firing_dcmds: megasas_free_ctrl_mem(instance); + megasas_destroy_debugfs(instance); + scsi_host_put(host); pci_disable_device(pdev); @@ -7400,6 +7809,9 @@ static void megasas_shutdown(struct pci_dev *pdev) { struct megasas_instance *instance = pci_get_drvdata(pdev); + if (!instance) + return; + instance->unload = 1; if (megasas_wait_for_adapter_operational(instance)) @@ -7545,7 +7957,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) || ((ioc->frame.hdr.cmd == MFI_CMD_NVME) && - !instance->support_nvme_passthru)) { + !instance->support_nvme_passthru) || + ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) && + !instance->support_pci_lane_margining)) { dev_err(&instance->pdev->dev, "Received invalid ioctl command 0x%x\n", ioc->frame.hdr.cmd); @@ -7581,10 +7995,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, opcode = le32_to_cpu(cmd->frame->dcmd.opcode); if (opcode == MR_DCMD_CTRL_SHUTDOWN) { + mutex_lock(&instance->reset_mutex); if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) { megasas_return_cmd(instance, cmd); + mutex_unlock(&instance->reset_mutex); return -1; } + mutex_unlock(&instance->reset_mutex); } if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) { @@ -8026,6 +8443,14 @@ support_nvme_encapsulation_show(struct device_driver *dd, char *buf) static DRIVER_ATTR_RO(support_nvme_encapsulation); +static ssize_t +support_pci_lane_margining_show(struct device_driver *dd, char *buf) +{ + return sprintf(buf, "%u\n", support_pci_lane_margining); +} + +static DRIVER_ATTR_RO(support_pci_lane_margining); + static inline void megasas_remove_scsi_device(struct scsi_device *sdev) { sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n"); @@ -8174,7 +8599,7 @@ megasas_aen_polling(struct work_struct *work) struct megasas_instance *instance = ev->instance; union megasas_evt_class_locale class_locale; int event_type = 0; - u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME; + u32 seq_num; int error; u8 dcmd_ret = DCMD_SUCCESS; @@ -8184,10 +8609,6 @@ megasas_aen_polling(struct work_struct *work) return; } - /* Adjust event workqueue thread wait time for VF mode */ - if (instance->requestorId) - wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF; - /* Don't run the event workqueue thread if OCR is running */ mutex_lock(&instance->reset_mutex); @@ -8299,6 +8720,7 @@ static int __init megasas_init(void) support_poll_for_event = 2; support_device_change = 1; support_nvme_encapsulation = true; + support_pci_lane_margining = true; memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info)); @@ -8314,6 +8736,8 @@ static int __init megasas_init(void) megasas_mgmt_majorno = rval; + megasas_init_debugfs(); + /* * Register ourselves as PCI hotplug module */ @@ -8353,8 +8777,17 @@ static int __init megasas_init(void) if (rval) goto err_dcf_support_nvme_encapsulation; + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_support_pci_lane_margining); + if (rval) + goto err_dcf_support_pci_lane_margining; + return rval; +err_dcf_support_pci_lane_margining: + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_support_nvme_encapsulation); + err_dcf_support_nvme_encapsulation: driver_remove_file(&megasas_pci_driver.driver, &driver_attr_support_device_change); @@ -8373,6 +8806,7 @@ err_dcf_rel_date: err_dcf_attr_ver: pci_unregister_driver(&megasas_pci_driver); err_pcidrv: + megasas_exit_debugfs(); unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); return rval; } @@ -8393,8 +8827,11 @@ static void __exit megasas_exit(void) driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_support_nvme_encapsulation); + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_support_pci_lane_margining); pci_unregister_driver(&megasas_pci_driver); + megasas_exit_debugfs(); unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); } diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c new file mode 100644 index 000000000000..c69760775efa --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c @@ -0,0 +1,179 @@ +/* + * Linux MegaRAID driver for SAS based RAID controllers + * + * Copyright (c) 2003-2018 LSI Corporation. + * Copyright (c) 2003-2018 Avago Technologies. + * Copyright (c) 2003-2018 Broadcom Inc. + * + * 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 program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Broadcom Inc. + * Kashyap Desai <kashyap.desai@broadcom.com> + * Sumit Saxena <sumit.saxena@broadcom.com> + * Shivasharan S <shivasharan.srikanteshwara@broadcom.com> + * + * Send feedback to: megaraidlinux.pdl@broadcom.com + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/compat.h> +#include <linux/irq_poll.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> + +#include "megaraid_sas_fusion.h" +#include "megaraid_sas.h" + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> + +struct dentry *megasas_debugfs_root; + +static ssize_t +megasas_debugfs_read(struct file *filp, char __user *ubuf, size_t cnt, + loff_t *ppos) +{ + struct megasas_debugfs_buffer *debug = filp->private_data; + + if (!debug || !debug->buf) + return 0; + + return simple_read_from_buffer(ubuf, cnt, ppos, debug->buf, debug->len); +} + +static int +megasas_debugfs_raidmap_open(struct inode *inode, struct file *file) +{ + struct megasas_instance *instance = inode->i_private; + struct megasas_debugfs_buffer *debug; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + + debug = kzalloc(sizeof(struct megasas_debugfs_buffer), GFP_KERNEL); + if (!debug) + return -ENOMEM; + + debug->buf = (void *)fusion->ld_drv_map[(instance->map_id & 1)]; + debug->len = fusion->drv_map_sz; + file->private_data = debug; + + return 0; +} + +static int +megasas_debugfs_release(struct inode *inode, struct file *file) +{ + struct megasas_debug_buffer *debug = file->private_data; + + if (!debug) + return 0; + + file->private_data = NULL; + kfree(debug); + return 0; +} + +static const struct file_operations megasas_debugfs_raidmap_fops = { + .owner = THIS_MODULE, + .open = megasas_debugfs_raidmap_open, + .read = megasas_debugfs_read, + .release = megasas_debugfs_release, +}; + +/* + * megasas_init_debugfs : Create debugfs root for megaraid_sas driver + */ +void megasas_init_debugfs(void) +{ + megasas_debugfs_root = debugfs_create_dir("megaraid_sas", NULL); + if (!megasas_debugfs_root) + pr_info("Cannot create debugfs root\n"); +} + +/* + * megasas_exit_debugfs : Remove debugfs root for megaraid_sas driver + */ +void megasas_exit_debugfs(void) +{ + debugfs_remove_recursive(megasas_debugfs_root); +} + +/* + * megasas_setup_debugfs : Setup debugfs per Fusion adapter + * instance: Soft instance of adapter + */ +void +megasas_setup_debugfs(struct megasas_instance *instance) +{ + char name[64]; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + + if (fusion) { + snprintf(name, sizeof(name), + "scsi_host%d", instance->host->host_no); + if (!instance->debugfs_root) { + instance->debugfs_root = + debugfs_create_dir(name, megasas_debugfs_root); + if (!instance->debugfs_root) { + dev_err(&instance->pdev->dev, + "Cannot create per adapter debugfs directory\n"); + return; + } + } + + snprintf(name, sizeof(name), "raidmap_dump"); + instance->raidmap_dump = + debugfs_create_file(name, S_IRUGO, + instance->debugfs_root, instance, + &megasas_debugfs_raidmap_fops); + if (!instance->raidmap_dump) { + dev_err(&instance->pdev->dev, + "Cannot create raidmap debugfs file\n"); + debugfs_remove(instance->debugfs_root); + return; + } + } + +} + +/* + * megasas_destroy_debugfs : Destroy debugfs per Fusion adapter + * instance: Soft instance of adapter + */ +void megasas_destroy_debugfs(struct megasas_instance *instance) +{ + debugfs_remove_recursive(instance->debugfs_root); +} + +#else +void megasas_init_debugfs(void) +{ +} +void megasas_exit_debugfs(void) +{ +} +void megasas_setup_debugfs(struct megasas_instance *instance) +{ +} +void megasas_destroy_debugfs(struct megasas_instance *instance) +{ +} +#endif /*CONFIG_DEBUG_FS*/ diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 87c2c0472c8f..50b8c1b12767 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Linux MegaRAID driver for SAS based RAID controllers * @@ -5,19 +6,6 @@ * Copyright (c) 2013-2016 Avago Technologies * Copyright (c) 2016-2018 Broadcom Inc. * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - * * FILE: megaraid_sas_fp.c * * Authors: Broadcom Inc. @@ -45,6 +33,7 @@ #include <linux/compat.h> #include <linux/blkdev.h> #include <linux/poll.h> +#include <linux/irq_poll.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -57,7 +46,7 @@ #define LB_PENDING_CMDS_DEFAULT 4 static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; -module_param(lb_pending_cmds, int, S_IRUGO); +module_param(lb_pending_cmds, int, 0444); MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding " "threshold. Valid Values are 1-128. Default: 4"); @@ -901,6 +890,77 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, } /* + * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation + * @instance: Adapter soft state + * @ld: LD index + * @stripNo: Strip Number + * @io_info: IO info structure pointer + * pRAID_Context: RAID context pointer + * map: RAID map pointer + * + * This routine calculates the logical arm, data Arm, row number and parity arm + * for R56 CTIO write operation. + */ +static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance, + u32 ld, u64 stripNo, + struct IO_REQUEST_INFO *io_info, + struct RAID_CONTEXT_G35 *pRAID_Context, + struct MR_DRV_RAID_MAP_ALL *map) +{ + struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + u8 span, dataArms, arms, dataArm, logArm; + s8 rightmostParityArm, PParityArm; + u64 rowNum; + u64 *pdBlock = &io_info->pdBlock; + + dataArms = raid->rowDataSize; + arms = raid->rowSize; + + rowNum = mega_div64_32(stripNo, dataArms); + /* parity disk arm, first arm is 0 */ + rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms); + + /* logical arm within row */ + logArm = mega_mod64(stripNo, dataArms); + /* physical arm for data */ + dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms); + + if (raid->spanDepth == 1) { + span = 0; + } else { + span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map); + if (span == SPAN_INVALID) + return; + } + + if (raid->level == 6) { + /* P Parity arm, note this can go negative adjust if negative */ + PParityArm = (arms - 2) - mega_mod64(rowNum, arms); + + if (PParityArm < 0) + PParityArm += arms; + + /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */ + pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm; + pRAID_Context->flow_specific.r56_arm_map |= + (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT); + } else { + pRAID_Context->flow_specific.r56_arm_map |= + (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT); + } + + pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum); + pRAID_Context->flow_specific.r56_arm_map |= + (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT); + cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map); + pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm; + pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD << + MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); + + return; +} + +/* ****************************************************************************** * * MR_BuildRaidContext function @@ -966,6 +1026,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, stripSize = 1 << raid->stripeShift; stripe_mask = stripSize-1; + io_info->data_arms = raid->rowDataSize; /* * calculate starting row and stripe, and number of strips and rows @@ -1107,6 +1168,13 @@ MR_BuildRaidContext(struct megasas_instance *instance, /* save pointer to raid->LUN array */ *raidLUN = raid->LUN; + /* Aero R5/6 Division Offload for WRITE */ + if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) { + mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info, + (struct RAID_CONTEXT_G35 *)pRAID_Context, + map); + return true; + } /*Get Phy Params only if FP capable, or else leave it to MR firmware to do the calculation.*/ diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 1d17128030cd..a32b3f0fcd15 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Linux MegaRAID driver for SAS based RAID controllers * @@ -5,19 +6,6 @@ * Copyright (c) 2013-2016 Avago Technologies * Copyright (c) 2016-2018 Broadcom Inc. * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - * * FILE: megaraid_sas_fusion.c * * Authors: Broadcom Inc. @@ -47,6 +35,7 @@ #include <linux/poll.h> #include <linux/vmalloc.h> #include <linux/workqueue.h> +#include <linux/irq_poll.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -99,6 +88,62 @@ extern u32 megasas_readl(struct megasas_instance *instance, const volatile void __iomem *addr); /** + * megasas_adp_reset_wait_for_ready - initiate chip reset and wait for + * controller to come to ready state + * @instance - adapter's soft state + * @do_adp_reset - If true, do a chip reset + * @ocr_context - If called from OCR context this will + * be set to 1, else 0 + * + * This function initates a chip reset followed by a wait for controller to + * transition to ready state. + * During this, driver will block all access to PCI config space from userspace + */ +int +megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, + bool do_adp_reset, + int ocr_context) +{ + int ret = FAILED; + + /* + * Block access to PCI config space from userspace + * when diag reset is initiated from driver + */ + if (megasas_dbg_lvl & OCR_DEBUG) + dev_info(&instance->pdev->dev, + "Block access to PCI config space %s %d\n", + __func__, __LINE__); + + pci_cfg_access_lock(instance->pdev); + + if (do_adp_reset) { + if (instance->instancet->adp_reset + (instance, instance->reg_set)) + goto out; + } + + /* Wait for FW to become ready */ + if (megasas_transition_to_ready(instance, ocr_context)) { + dev_warn(&instance->pdev->dev, + "Failed to transition controller to ready for scsi%d.\n", + instance->host->host_no); + goto out; + } + + ret = SUCCESS; +out: + if (megasas_dbg_lvl & OCR_DEBUG) + dev_info(&instance->pdev->dev, + "Unlock access to PCI config space %s %d\n", + __func__, __LINE__); + + pci_cfg_access_unlock(instance->pdev); + + return ret; +} + +/** * megasas_check_same_4gb_region - check if allocation * crosses same 4GB boundary or not * @instance - adapter's soft instance @@ -145,7 +190,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance) writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); + dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n", + __func__, readl(®s->outbound_intr_mask)); } /** @@ -156,14 +202,14 @@ void megasas_disable_intr_fusion(struct megasas_instance *instance) { u32 mask = 0xFFFFFFFF; - u32 status; struct megasas_register_set __iomem *regs; regs = instance->reg_set; instance->mask_interrupts = 1; writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ - status = readl(®s->outbound_intr_mask); + dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n", + __func__, readl(®s->outbound_intr_mask)); } int @@ -219,21 +265,17 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, } /** - * megasas_fire_cmd_fusion - Sends command to the FW - * @instance: Adapter soft state - * @req_desc: 64bit Request descriptor - * - * Perform PCI Write. + * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor + * @instance: Adapter soft state + * @req_desc: 64bit Request descriptor */ - static void -megasas_fire_cmd_fusion(struct megasas_instance *instance, +megasas_write_64bit_req_desc(struct megasas_instance *instance, union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) { #if defined(writeq) && defined(CONFIG_64BIT) u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | le32_to_cpu(req_desc->u.low)); - writeq(req_data, &instance->reg_set->inbound_low_queue_port); #else unsigned long flags; @@ -242,12 +284,30 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, &instance->reg_set->inbound_low_queue_port); writel(le32_to_cpu(req_desc->u.high), &instance->reg_set->inbound_high_queue_port); - mmiowb(); spin_unlock_irqrestore(&instance->hba_lock, flags); #endif } /** + * megasas_fire_cmd_fusion - Sends command to the FW + * @instance: Adapter soft state + * @req_desc: 32bit or 64bit Request descriptor + * + * Perform PCI Write. AERO SERIES supports 32 bit Descriptor. + * Prior to AERO_SERIES support 64 bit Descriptor. + */ +static void +megasas_fire_cmd_fusion(struct megasas_instance *instance, + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) +{ + if (instance->atomic_desc_support) + writel(le32_to_cpu(req_desc->u.low), + &instance->reg_set->inbound_single_queue_port); + else + megasas_write_64bit_req_desc(instance, req_desc); +} + +/** * megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here * @instance: Adapter soft state * fw_boot_context: Whether this function called during probe or after OCR @@ -937,6 +997,7 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, { int i; struct megasas_header *frame_hdr = &cmd->frame->hdr; + u32 status_reg; u32 msecs = seconds * 1000; @@ -946,6 +1007,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) { rmb(); msleep(20); + if (!(i % 5000)) { + status_reg = instance->instancet->read_fw_status_reg(instance) + & MFI_STATE_MASK; + if (status_reg == MFI_STATE_FAULT) + break; + } } if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS) @@ -979,6 +1046,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) u32 scratch_pad_1; ktime_t time; bool cur_fw_64bit_dma_capable; + bool cur_intr_coalescing; fusion = instance->ctrl_context; @@ -1012,6 +1080,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) goto fail_fw_init; } + cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? + true : false; + + if ((instance->low_latency_index_start == + MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing) + instance->perf_mode = MR_BALANCED_PERF_MODE; + + dev_info(&instance->pdev->dev, "Performance mode :%s\n", + MEGASAS_PERF_MODE_2STR(instance->perf_mode)); + instance->fw_sync_cache_support = (scratch_pad_1 & MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0; dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n", @@ -1096,6 +1174,22 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) cpu_to_le32(lower_32_bits(ioc_init_handle)); init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST)); + /* + * Each bit in replyqueue_mask represents one group of MSI-x vectors + * (each group has 8 vectors) + */ + switch (instance->perf_mode) { + case MR_BALANCED_PERF_MODE: + init_frame->replyqueue_mask = + cpu_to_le16(~(~0 << instance->low_latency_index_start/8)); + break; + case MR_IOPS_PERF_MODE: + init_frame->replyqueue_mask = + cpu_to_le16(~(~0 << instance->msix_vectors/8)); + break; + } + + req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr)); req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr)); req_desc.MFAIo.RequestFlags = @@ -1114,7 +1208,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) break; } - megasas_fire_cmd_fusion(instance, &req_desc); + /* For AERO also, IOC_INIT requires 64 bit descriptor write */ + megasas_write_64bit_req_desc(instance, &req_desc); wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS); @@ -1124,6 +1219,17 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) goto fail_fw_init; } + if (instance->adapter_type >= AERO_SERIES) { + scratch_pad_1 = megasas_readl + (instance, &instance->reg_set->outbound_scratch_pad_1); + + instance->atomic_desc_support = + (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0; + + dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n", + instance->atomic_desc_support ? "Yes" : "No"); + } + return 0; fail_fw_init: @@ -1146,7 +1252,7 @@ fail_fw_init: int megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { int ret = 0; - u32 pd_seq_map_sz; + size_t pd_seq_map_sz; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct fusion_context *fusion = instance->ctrl_context; @@ -1155,9 +1261,7 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)]; pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)]; - pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + - (sizeof(struct MR_PD_CFG_SEQ) * - (MAX_PHYSICAL_DEVICES - 1)); + pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1); cmd = megasas_get_cmd(instance); if (!cmd) { @@ -1638,6 +1742,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) struct fusion_context *fusion; u32 scratch_pad_1; int i = 0, count; + u32 status_reg; fusion = instance->ctrl_context; @@ -1720,8 +1825,21 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) if (megasas_alloc_cmds_fusion(instance)) goto fail_alloc_cmds; - if (megasas_ioc_init_fusion(instance)) - goto fail_ioc_init; + if (megasas_ioc_init_fusion(instance)) { + status_reg = instance->instancet->read_fw_status_reg(instance); + if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) && + (status_reg & MFI_RESET_ADAPTER)) { + /* Do a chip reset and then retry IOC INIT once */ + if (megasas_adp_reset_wait_for_ready + (instance, true, 0) == FAILED) + goto fail_ioc_init; + + if (megasas_ioc_init_fusion(instance)) + goto fail_ioc_init; + } else { + goto fail_ioc_init; + } + } megasas_display_intel_branding(instance); if (megasas_get_ctrl_info(instance)) { @@ -1733,6 +1851,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) instance->flag_ieee = 1; instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT; + instance->threshold_reply_count = instance->max_fw_cmds / 4; fusion->fast_path_io = 0; if (megasas_allocate_raid_maps(instance)) @@ -1983,7 +2102,6 @@ megasas_is_prp_possible(struct megasas_instance *instance, mega_mod64(sg_dma_address(sg_scmd), mr_nvme_pg_size)) { build_prp = false; - atomic_inc(&instance->sge_holes_type1); break; } } @@ -1993,7 +2111,6 @@ megasas_is_prp_possible(struct megasas_instance *instance, sg_dma_len(sg_scmd)), mr_nvme_pg_size))) { build_prp = false; - atomic_inc(&instance->sge_holes_type2); break; } } @@ -2002,7 +2119,6 @@ megasas_is_prp_possible(struct megasas_instance *instance, if (mega_mod64(sg_dma_address(sg_scmd), mr_nvme_pg_size)) { build_prp = false; - atomic_inc(&instance->sge_holes_type3); break; } } @@ -2135,7 +2251,6 @@ megasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd, main_chain_element->Length = cpu_to_le32(num_prp_in_chain * sizeof(u64)); - atomic_inc(&instance->prp_sgl); return build_prp; } @@ -2210,7 +2325,6 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, memset(sgl_ptr, 0, instance->max_chain_frame_sz); } } - atomic_inc(&instance->ieee_sgl); } /** @@ -2522,9 +2636,10 @@ static void megasas_stream_detect(struct megasas_instance *instance, * */ static void -megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context, - struct MR_LD_RAID *raid, bool fp_possible, - u8 is_read, u32 scsi_buff_len) +megasas_set_raidflag_cpu_affinity(struct fusion_context *fusion, + union RAID_CONTEXT_UNION *praid_context, + struct MR_LD_RAID *raid, bool fp_possible, + u8 is_read, u32 scsi_buff_len) { u8 cpu_sel = MR_RAID_CTX_CPUSEL_0; struct RAID_CONTEXT_G35 *rctx_g35; @@ -2582,11 +2697,11 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context, * vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS. * IO Subtype is not bitmap. */ - if ((raid->level == 1) && (!is_read)) { - if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE) - praid_context->raid_context_g35.raid_flags = - (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT - << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); + if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) && + (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) { + praid_context->raid_context_g35.raid_flags = + (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT + << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); } } @@ -2692,6 +2807,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID; scsi_buff_len = scsi_bufflen(scp); io_request->DataLength = cpu_to_le32(scsi_buff_len); + io_info.data_arms = 1; if (scp->sc_data_direction == DMA_FROM_DEVICE) io_info.isRead = 1; @@ -2711,8 +2827,19 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, fp_possible = (io_info.fpOkForIo > 0) ? true : false; } - cmd->request_desc->SCSIIO.MSIxIndex = - instance->reply_map[raw_smp_processor_id()]; + if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && + atomic_read(&scp->device->device_busy) > + (io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH)) + cmd->request_desc->SCSIIO.MSIxIndex = + mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) / + MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start); + else if (instance->msix_load_balance) + cmd->request_desc->SCSIIO.MSIxIndex = + (mega_mod64(atomic64_add_return(1, &instance->total_io_count), + instance->msix_vectors)); + else + cmd->request_desc->SCSIIO.MSIxIndex = + instance->reply_map[raw_smp_processor_id()]; if (instance->adapter_type >= VENTURA_SERIES) { /* FP for Optimal raid level 1. @@ -2730,8 +2857,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (instance->host->can_queue)) { fp_possible = false; atomic_dec(&instance->fw_outstanding); - } else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) || - (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) { + } else if (fusion->pcie_bw_limitation && + ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) || + (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) { fp_possible = false; atomic_dec(&instance->fw_outstanding); if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE) @@ -2756,7 +2884,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, /* If raid is NULL, set CPU affinity to default CPU0 */ if (raid) - megasas_set_raidflag_cpu_affinity(&io_request->RaidContext, + megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext, raid, fp_possible, io_info.isRead, scsi_buff_len); else @@ -2772,10 +2900,6 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (instance->adapter_type == INVADER_SERIES) { - if (rctx->reg_lock_flags == REGION_TYPE_UNUSED) - cmd->request_desc->SCSIIO.RequestFlags = - (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); rctx->type = MPI2_TYPE_CUDA; rctx->nseg = 0x1; io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); @@ -2983,50 +3107,71 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; /* If FW supports PD sequence number */ - if (instance->use_seqnum_jbod_fp && - instance->pd_list[pd_index].driveType == TYPE_DISK) { - /* TgtId must be incremented by 255 as jbod seq number is index - * below raid map - */ - /* More than 256 PD/JBOD support for Ventura */ - if (instance->support_morethan256jbod) - pRAID_Context->virtual_disk_tgt_id = - pd_sync->seq[pd_index].pd_target_id; - else - pRAID_Context->virtual_disk_tgt_id = - cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); - pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum; - io_request->DevHandle = pd_sync->seq[pd_index].devHandle; - if (instance->adapter_type >= VENTURA_SERIES) { - io_request->RaidContext.raid_context_g35.routing_flags |= - (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); - io_request->RaidContext.raid_context_g35.nseg_type |= - (1 << RAID_CONTEXT_NSEG_SHIFT); - io_request->RaidContext.raid_context_g35.nseg_type |= - (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); + if (instance->support_seqnum_jbod_fp) { + if (instance->use_seqnum_jbod_fp && + instance->pd_list[pd_index].driveType == TYPE_DISK) { + + /* More than 256 PD/JBOD support for Ventura */ + if (instance->support_morethan256jbod) + pRAID_Context->virtual_disk_tgt_id = + pd_sync->seq[pd_index].pd_target_id; + else + pRAID_Context->virtual_disk_tgt_id = + cpu_to_le16(device_id + + (MAX_PHYSICAL_DEVICES - 1)); + pRAID_Context->config_seq_num = + pd_sync->seq[pd_index].seqNum; + io_request->DevHandle = + pd_sync->seq[pd_index].devHandle; + if (instance->adapter_type >= VENTURA_SERIES) { + io_request->RaidContext.raid_context_g35.routing_flags |= + (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); + io_request->RaidContext.raid_context_g35.nseg_type |= + (1 << RAID_CONTEXT_NSEG_SHIFT); + io_request->RaidContext.raid_context_g35.nseg_type |= + (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); + } else { + pRAID_Context->type = MPI2_TYPE_CUDA; + pRAID_Context->nseg = 0x1; + pRAID_Context->reg_lock_flags |= + (MR_RL_FLAGS_SEQ_NUM_ENABLE | + MR_RL_FLAGS_GRANT_DESTINATION_CUDA); + } } else { - pRAID_Context->type = MPI2_TYPE_CUDA; - pRAID_Context->nseg = 0x1; - pRAID_Context->reg_lock_flags |= - (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA); + pRAID_Context->virtual_disk_tgt_id = + cpu_to_le16(device_id + + (MAX_PHYSICAL_DEVICES - 1)); + pRAID_Context->config_seq_num = 0; + io_request->DevHandle = cpu_to_le16(0xFFFF); } - } else if (fusion->fast_path_io) { - pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); - pRAID_Context->config_seq_num = 0; - local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; - io_request->DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; } else { - /* Want to send all IO via FW path */ pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); pRAID_Context->config_seq_num = 0; - io_request->DevHandle = cpu_to_le16(0xFFFF); + + if (fusion->fast_path_io) { + local_map_ptr = + fusion->ld_drv_map[(instance->map_id & 1)]; + io_request->DevHandle = + local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + } else { + io_request->DevHandle = cpu_to_le16(0xFFFF); + } } cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; - cmd->request_desc->SCSIIO.MSIxIndex = - instance->reply_map[raw_smp_processor_id()]; + if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && + atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH) + cmd->request_desc->SCSIIO.MSIxIndex = + mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) / + MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start); + else if (instance->msix_load_balance) + cmd->request_desc->SCSIIO.MSIxIndex = + (mega_mod64(atomic64_add_return(1, &instance->total_io_count), + instance->msix_vectors)); + else + cmd->request_desc->SCSIIO.MSIxIndex = + instance->reply_map[raw_smp_processor_id()]; if (!fp_possible) { /* system pd firmware path */ @@ -3206,9 +3351,9 @@ void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle; r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle; r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle; - cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid = cpu_to_le16(r1_cmd->index); - r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid = cpu_to_le16(cmd->index); /*MSIxIndex of both commands request descriptors should be same*/ r1_cmd->request_desc->SCSIIO.MSIxIndex = @@ -3326,7 +3471,7 @@ megasas_complete_r1_command(struct megasas_instance *instance, rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35; fusion = instance->ctrl_context; - peer_smid = le16_to_cpu(rctx_g35->smid.peer_smid); + peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid); r1_cmd = fusion->cmd_list[peer_smid - 1]; scmd_local = cmd->scmd; @@ -3366,7 +3511,8 @@ megasas_complete_r1_command(struct megasas_instance *instance, * Completes all commands that is in reply descriptor queue */ int -complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) +complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, + struct megasas_irq_context *irq_context) { union MPI2_REPLY_DESCRIPTORS_UNION *desc; struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc; @@ -3499,7 +3645,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) * number of reply counts and still there are more replies in reply queue * pending to be completed */ - if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { + if (threshold_reply_count >= instance->threshold_reply_count) { if (instance->msix_combined) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], @@ -3509,23 +3655,46 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[0]); threshold_reply_count = 0; + if (irq_context) { + if (!irq_context->irq_poll_scheduled) { + irq_context->irq_poll_scheduled = true; + irq_context->irq_line_enable = true; + irq_poll_sched(&irq_context->irqpoll); + } + return num_completed; + } } } - if (!num_completed) - return IRQ_NONE; + if (num_completed) { + wmb(); + if (instance->msix_combined) + writel(((MSIxIndex & 0x7) << 24) | + fusion->last_reply_idx[MSIxIndex], + instance->reply_post_host_index_addr[MSIxIndex/8]); + else + writel((MSIxIndex << 24) | + fusion->last_reply_idx[MSIxIndex], + instance->reply_post_host_index_addr[0]); + megasas_check_and_restore_queue_depth(instance); + } + return num_completed; +} - wmb(); - if (instance->msix_combined) - writel(((MSIxIndex & 0x7) << 24) | - fusion->last_reply_idx[MSIxIndex], - instance->reply_post_host_index_addr[MSIxIndex/8]); - else - writel((MSIxIndex << 24) | - fusion->last_reply_idx[MSIxIndex], - instance->reply_post_host_index_addr[0]); - megasas_check_and_restore_queue_depth(instance); - return IRQ_HANDLED; +/** + * megasas_enable_irq_poll() - enable irqpoll + */ +static void megasas_enable_irq_poll(struct megasas_instance *instance) +{ + u32 count, i; + struct megasas_irq_context *irq_ctx; + + count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + + for (i = 0; i < count; i++) { + irq_ctx = &instance->irq_context[i]; + irq_poll_enable(&irq_ctx->irqpoll); + } } /** @@ -3537,11 +3706,51 @@ void megasas_sync_irqs(unsigned long instance_addr) u32 count, i; struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + struct megasas_irq_context *irq_ctx; count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { synchronize_irq(pci_irq_vector(instance->pdev, i)); + irq_ctx = &instance->irq_context[i]; + irq_poll_disable(&irq_ctx->irqpoll); + if (irq_ctx->irq_poll_scheduled) { + irq_ctx->irq_poll_scheduled = false; + enable_irq(irq_ctx->os_irq); + } + } +} + +/** + * megasas_irqpoll() - process a queue for completed reply descriptors + * @irqpoll: IRQ poll structure associated with queue to poll. + * @budget: Threshold of reply descriptors to process per poll. + * + * Return: The number of entries processed. + */ + +int megasas_irqpoll(struct irq_poll *irqpoll, int budget) +{ + struct megasas_irq_context *irq_ctx; + struct megasas_instance *instance; + int num_entries; + + irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll); + instance = irq_ctx->instance; + + if (irq_ctx->irq_line_enable) { + disable_irq(irq_ctx->os_irq); + irq_ctx->irq_line_enable = false; + } + + num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx); + if (num_entries < budget) { + irq_poll_complete(irqpoll); + irq_ctx->irq_poll_scheduled = false; + enable_irq(irq_ctx->os_irq); + } + + return num_entries; } /** @@ -3564,7 +3773,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr) return; for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) - complete_cmd_fusion(instance, MSIxIndex); + complete_cmd_fusion(instance, MSIxIndex, NULL); } /** @@ -3579,6 +3788,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) if (instance->mask_interrupts) return IRQ_NONE; +#if defined(ENABLE_IRQ_POLL) + if (irq_context->irq_poll_scheduled) + return IRQ_HANDLED; +#endif + if (!instance->msix_vectors) { mfiStatus = instance->instancet->clear_intr(instance); if (!mfiStatus) @@ -3591,7 +3805,8 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) return IRQ_HANDLED; } - return complete_cmd_fusion(instance, irq_context->MSIxIndex); + return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context) + ? IRQ_HANDLED : IRQ_NONE; } /** @@ -3856,7 +4071,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance, static inline void megasas_trigger_snap_dump(struct megasas_instance *instance) { int j; - u32 fw_state; + u32 fw_state, abs_state; if (!instance->disableOnlineCtrlReset) { dev_info(&instance->pdev->dev, "Trigger snap dump\n"); @@ -3866,11 +4081,13 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance) } for (j = 0; j < instance->snapdump_wait_time; j++) { - fw_state = instance->instancet->read_fw_status_reg(instance) & - MFI_STATE_MASK; + abs_state = instance->instancet->read_fw_status_reg(instance); + fw_state = abs_state & MFI_STATE_MASK; if (fw_state == MFI_STATE_FAULT) { - dev_err(&instance->pdev->dev, - "Found FW in FAULT state, after snap dump trigger\n"); + dev_printk(KERN_ERR, &instance->pdev->dev, + "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n", + abs_state & MFI_STATE_FAULT_CODE, + abs_state & MFI_STATE_FAULT_SUBCODE, __func__); return; } msleep(1000); @@ -3882,7 +4099,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, int reason, int *convert) { int i, outstanding, retval = 0, hb_seconds_missed = 0; - u32 fw_state; + u32 fw_state, abs_state; u32 waittime_for_io_completion; waittime_for_io_completion = @@ -3901,12 +4118,13 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, for (i = 0; i < waittime_for_io_completion; i++) { /* Check if firmware is in fault state */ - fw_state = instance->instancet->read_fw_status_reg(instance) & - MFI_STATE_MASK; + abs_state = instance->instancet->read_fw_status_reg(instance); + fw_state = abs_state & MFI_STATE_MASK; if (fw_state == MFI_STATE_FAULT) { - dev_warn(&instance->pdev->dev, "Found FW in FAULT state," - " will reset adapter scsi%d.\n", - instance->host->host_no); + dev_printk(KERN_ERR, &instance->pdev->dev, + "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n", + abs_state & MFI_STATE_FAULT_CODE, + abs_state & MFI_STATE_FAULT_SUBCODE, __func__); megasas_complete_cmd_dpc_fusion((unsigned long)instance); if (instance->requestorId && reason) { dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT" @@ -4055,6 +4273,13 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) } break; + case MFI_CMD_TOOLBOX: + if (!instance->support_pci_lane_margining) { + cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD; + result = COMPLETE_CMD; + } + + break; default: break; } @@ -4278,6 +4503,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, instance->instancet->disable_intr(instance); megasas_sync_irqs((unsigned long)instance); instance->instancet->enable_intr(instance); + megasas_enable_irq_poll(instance); if (scsi_lookup->scmd == NULL) break; } @@ -4291,6 +4517,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, megasas_sync_irqs((unsigned long)instance); rc = megasas_track_scsiio(instance, id, channel); instance->instancet->enable_intr(instance); + megasas_enable_irq_poll(instance); break; case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: @@ -4389,9 +4616,6 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - scmd_printk(KERN_INFO, scmd, "task abort called for scmd(%p)\n", scmd); - scsi_print_command(scmd); - if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," "SCSI host:%d\n", instance->host->host_no); @@ -4419,7 +4643,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) if (!smid) { ret = SUCCESS; scmd_printk(KERN_NOTICE, scmd, "Command for which abort is" - " issued is not found in oustanding commands\n"); + " issued is not found in outstanding commands\n"); mutex_unlock(&instance->reset_mutex); goto out; } @@ -4434,7 +4658,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) goto out; } sdev_printk(KERN_INFO, scmd->device, - "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n", + "attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n", scmd, devhandle); mr_device_priv_data->tm_busy = 1; @@ -4445,9 +4669,12 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) mr_device_priv_data->tm_busy = 0; mutex_unlock(&instance->reset_mutex); -out: - sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", + scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n", ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); +out: + scsi_print_command(scmd); + if (megasas_dbg_lvl & TM_DEBUG) + megasas_dump_fusion_io(scmd); return ret; } @@ -4470,9 +4697,6 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - sdev_printk(KERN_INFO, scmd->device, - "target reset called for scmd(%p)\n", scmd); - if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," "SCSI host:%d\n", instance->host->host_no); @@ -4481,8 +4705,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) } if (!mr_device_priv_data) { - sdev_printk(KERN_INFO, scmd->device, "device been deleted! " - "scmd(%p)\n", scmd); + sdev_printk(KERN_INFO, scmd->device, + "device been deleted! scmd: (0x%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; ret = SUCCESS; goto out; @@ -4505,7 +4729,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) } sdev_printk(KERN_INFO, scmd->device, - "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n", + "attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n", scmd, devhandle); mr_device_priv_data->tm_busy = 1; ret = megasas_issue_tm(instance, devhandle, @@ -4514,10 +4738,10 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) mr_device_priv_data); mr_device_priv_data->tm_busy = 0; mutex_unlock(&instance->reset_mutex); -out: - scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n", + scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n", (ret == SUCCESS) ? "SUCCESS" : "FAILED"); +out: return ret; } @@ -4562,12 +4786,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) struct megasas_instance *instance; struct megasas_cmd_fusion *cmd_fusion, *r1_cmd; struct fusion_context *fusion; - u32 abs_state, status_reg, reset_adapter; + u32 abs_state, status_reg, reset_adapter, fpio_count = 0; u32 io_timeout_in_crash_mode = 0; struct scsi_cmnd *scmd_local = NULL; struct scsi_device *sdev; int ret_target_prop = DCMD_FAILED; bool is_target_prop = false; + bool do_adp_reset = true; + int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES; instance = (struct megasas_instance *)shost->hostdata; fusion = instance->ctrl_context; @@ -4634,7 +4860,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) if (convert) reason = 0; - if (megasas_dbg_lvl & OCR_LOGS) + if (megasas_dbg_lvl & OCR_DEBUG) dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n"); /* Now return commands back to the OS */ @@ -4647,13 +4873,17 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) } scmd_local = cmd_fusion->scmd; if (cmd_fusion->scmd) { - if (megasas_dbg_lvl & OCR_LOGS) { + if (megasas_dbg_lvl & OCR_DEBUG) { sdev_printk(KERN_INFO, cmd_fusion->scmd->device, "SMID: 0x%x\n", cmd_fusion->index); - scsi_print_command(cmd_fusion->scmd); + megasas_dump_fusion_io(cmd_fusion->scmd); } + if (cmd_fusion->io_request->Function == + MPI2_FUNCTION_SCSI_IO_REQUEST) + fpio_count++; + scmd_local->result = megasas_check_mpio_paths(instance, scmd_local); @@ -4666,6 +4896,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) } } + dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n", + fpio_count); + atomic_set(&instance->fw_outstanding, 0); status_reg = instance->instancet->read_fw_status_reg(instance); @@ -4677,52 +4910,45 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) dev_warn(&instance->pdev->dev, "Reset not supported" ", killing adapter scsi%d.\n", instance->host->host_no); - megaraid_sas_kill_hba(instance); - instance->skip_heartbeat_timer_del = 1; - retval = FAILED; - goto out; + goto kill_hba; } /* Let SR-IOV VF & PF sync up if there was a HB failure */ if (instance->requestorId && !reason) { msleep(MEGASAS_OCR_SETTLE_TIME_VF); - goto transition_to_ready; + do_adp_reset = false; + max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF; } /* Now try to reset the chip */ - for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { - - if (instance->instancet->adp_reset - (instance, instance->reg_set)) + for (i = 0; i < max_reset_tries; i++) { + /* + * Do adp reset and wait for + * controller to transition to ready + */ + if (megasas_adp_reset_wait_for_ready(instance, + do_adp_reset, 1) == FAILED) continue; -transition_to_ready: + /* Wait for FW to become ready */ if (megasas_transition_to_ready(instance, 1)) { dev_warn(&instance->pdev->dev, "Failed to transition controller to ready for " "scsi%d.\n", instance->host->host_no); - if (instance->requestorId && !reason) - goto fail_kill_adapter; - else - continue; + continue; } megasas_reset_reply_desc(instance); megasas_fusion_update_can_queue(instance, OCR_CONTEXT); if (megasas_ioc_init_fusion(instance)) { - if (instance->requestorId && !reason) - goto fail_kill_adapter; - else - continue; + continue; } if (megasas_get_ctrl_info(instance)) { dev_info(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); - megaraid_sas_kill_hba(instance); - retval = FAILED; - goto out; + goto kill_hba; } megasas_refire_mgmt_cmd(instance); @@ -4751,7 +4977,7 @@ transition_to_ready: clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); - + megasas_enable_irq_poll(instance); shost_for_each_device(sdev, shost) { if ((instance->tgt_prop) && (instance->nvme_page_size)) @@ -4763,9 +4989,9 @@ transition_to_ready: atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); - dev_info(&instance->pdev->dev, "Interrupts are enabled and" - " controller is OPERATIONAL for scsi:%d\n", - instance->host->host_no); + dev_info(&instance->pdev->dev, + "Adapter is OPERATIONAL for scsi:%d\n", + instance->host->host_no); /* Restart SR-IOV heartbeat */ if (instance->requestorId) { @@ -4799,13 +5025,10 @@ transition_to_ready: goto out; } -fail_kill_adapter: /* Reset failed, kill the adapter */ dev_warn(&instance->pdev->dev, "Reset failed, killing " "adapter scsi%d.\n", instance->host->host_no); - megaraid_sas_kill_hba(instance); - instance->skip_heartbeat_timer_del = 1; - retval = FAILED; + goto kill_hba; } else { /* For VF: Restart HB timer if we didn't OCR */ if (instance->requestorId) { @@ -4813,8 +5036,15 @@ fail_kill_adapter: } clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); + megasas_enable_irq_poll(instance); atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); + goto out; } +kill_hba: + megaraid_sas_kill_hba(instance); + megasas_enable_irq_poll(instance); + instance->skip_heartbeat_timer_del = 1; + retval = FAILED; out: clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); mutex_unlock(&instance->reset_mutex); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 1481bf029490..c013c80fe4e6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Linux MegaRAID driver for SAS based RAID controllers * @@ -5,19 +6,6 @@ * Copyright (c) 2013-2016 Avago Technologies * Copyright (c) 2016-2018 Broadcom Inc. * - * 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 program. If not, see <http://www.gnu.org/licenses/>. - * * FILE: megaraid_sas_fusion.h * * Authors: Broadcom Inc. @@ -87,7 +75,8 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P = 3, MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q = 4, MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6, - MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7 + MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7, + MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD = 8 }; /* @@ -100,7 +89,6 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 -#define THRESHOLD_REPLY_COUNT 50 #define RAID_1_PEER_CMDS 2 #define JBOD_MAPS_COUNT 2 #define MEGASAS_REDUCE_QD_COUNT 64 @@ -152,12 +140,15 @@ struct RAID_CONTEXT_G35 { u16 timeout_value; /* 0x02 -0x03 */ u16 routing_flags; // 0x04 -0x05 routing flags u16 virtual_disk_tgt_id; /* 0x06 -0x07 */ - u64 reg_lock_row_lba; /* 0x08 - 0x0F */ + __le64 reg_lock_row_lba; /* 0x08 - 0x0F */ u32 reg_lock_length; /* 0x10 - 0x13 */ - union { - u16 next_lmid; /* 0x14 - 0x15 */ - u16 peer_smid; /* used for the raid 1/10 fp writes */ - } smid; + union { // flow specific + u16 rmw_op_index; /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/ + u16 peer_smid; /* 0x14 - 0x15, R1 Write: peer smid*/ + u16 r56_arm_map; /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */ + + } flow_specific; + u8 ex_status; /* 0x16 : OUT */ u8 status; /* 0x17 status */ u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4], @@ -248,6 +239,13 @@ union RAID_CONTEXT_UNION { #define RAID_CTX_SPANARM_SPAN_SHIFT (5) #define RAID_CTX_SPANARM_SPAN_MASK (0xE0) +/* LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */ +#define RAID_CTX_R56_Q_ARM_MASK (0x1F) +#define RAID_CTX_R56_P_ARM_SHIFT (5) +#define RAID_CTX_R56_P_ARM_MASK (0x3E0) +#define RAID_CTX_R56_LOG_ARM_SHIFT (10) +#define RAID_CTX_R56_LOG_ARM_MASK (0x7C00) + /* number of bits per index in U32 TrackStream */ #define BITS_PER_INDEX_STREAM 4 #define INVALID_STREAM_NUM 16 @@ -952,6 +950,7 @@ struct IO_REQUEST_INFO { u8 pd_after_lb; u16 r1_alt_dev_handle; /* raid 1/10 only */ bool ra_capable; + u8 data_arms; }; struct MR_LD_TARGET_SYNC { @@ -1336,7 +1335,8 @@ struct fusion_context { dma_addr_t ioc_init_request_phys; struct MPI2_IOC_INIT_REQUEST *ioc_init_request; struct megasas_cmd *ioc_init_cmd; - + bool pcie_bw_limitation; + bool r56_div_offload; }; union desc_value { @@ -1361,6 +1361,11 @@ struct MR_SNAPDUMP_PROPERTIES { u8 reserved[12]; }; +struct megasas_debugfs_buffer { + void *buf; + u32 len; +}; + void megasas_free_cmds_fusion(struct megasas_instance *instance); int megasas_ioc_init_fusion(struct megasas_instance *instance); u8 megasas_get_map_info(struct megasas_instance *instance); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index c9dc7740e9e7..74fb50644678 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware) * bus adaptor found on Power Macintosh computers. diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig index b736dbc80485..a072187875df 100644 --- a/drivers/scsi/mpt3sas/Kconfig +++ b/drivers/scsi/mpt3sas/Kconfig @@ -45,6 +45,7 @@ config SCSI_MPT3SAS depends on PCI && SCSI select SCSI_SAS_ATTRS select RAID_ATTRS + select IRQ_POLL ---help--- This driver supports PCI-Express SAS 12Gb/s Host Adapters. diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index a2f4a55c51be..167d79d145ca 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -1398,7 +1398,7 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_1 { U8 PCIBusNum; /*0x0E */ U8 PCIDomainSegment; /*0x0F */ U32 Reserved1; /*0x10 */ - U32 Reserved2; /*0x14 */ + U32 ProductSpecific; /* 0x14 */ } MPI2_CONFIG_PAGE_IOC_1, *PTR_MPI2_CONFIG_PAGE_IOC_1, Mpi2IOCPage1_t, *pMpi2IOCPage1_t; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 1d8c584ec1e9..684662888792 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -74,30 +74,55 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; #define MAX_HBA_QUEUE_DEPTH 30000 #define MAX_CHAIN_DEPTH 100000 static int max_queue_depth = -1; -module_param(max_queue_depth, int, 0); +module_param(max_queue_depth, int, 0444); MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); static int max_sgl_entries = -1; -module_param(max_sgl_entries, int, 0); +module_param(max_sgl_entries, int, 0444); MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); static int msix_disable = -1; -module_param(msix_disable, int, 0); +module_param(msix_disable, int, 0444); MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); static int smp_affinity_enable = 1; -module_param(smp_affinity_enable, int, S_IRUGO); +module_param(smp_affinity_enable, int, 0444); MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)"); static int max_msix_vectors = -1; -module_param(max_msix_vectors, int, 0); +module_param(max_msix_vectors, int, 0444); MODULE_PARM_DESC(max_msix_vectors, " max msix vectors"); +static int irqpoll_weight = -1; +module_param(irqpoll_weight, int, 0444); +MODULE_PARM_DESC(irqpoll_weight, + "irq poll weight (default= one fourth of HBA queue depth)"); + static int mpt3sas_fwfault_debug; MODULE_PARM_DESC(mpt3sas_fwfault_debug, " enable detection of firmware fault and halt firmware - (default=0)"); +static int perf_mode = -1; +module_param(perf_mode, int, 0444); +MODULE_PARM_DESC(perf_mode, + "Performance mode (only for Aero/Sea Generation), options:\n\t\t" + "0 - balanced: high iops mode is enabled &\n\t\t" + "interrupt coalescing is enabled only on high iops queues,\n\t\t" + "1 - iops: high iops mode is disabled &\n\t\t" + "interrupt coalescing is enabled on all queues,\n\t\t" + "2 - latency: high iops mode is disabled &\n\t\t" + "interrupt coalescing is enabled on all queues with timeout value 0xA,\n" + "\t\tdefault - default perf_mode is 'balanced'" + ); + +enum mpt3sas_perf_mode { + MPT_PERF_MODE_DEFAULT = -1, + MPT_PERF_MODE_BALANCED = 0, + MPT_PERF_MODE_IOPS = 1, + MPT_PERF_MODE_LATENCY = 2, +}; + static int _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); @@ -1277,7 +1302,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; - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); out: @@ -1382,20 +1407,30 @@ union reply_descriptor { } u; }; +static u32 base_mod64(u64 dividend, u32 divisor) +{ + u32 remainder; + + if (!divisor) + pr_err("mpt3sas: DIVISOR is zero, in div fn\n"); + remainder = do_div(dividend, divisor); + return remainder; +} + /** - * _base_interrupt - MPT adapter (IOC) specific interrupt handler. - * @irq: irq number (not used) - * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure + * _base_process_reply_queue - Process reply descriptors from reply + * descriptor post queue. + * @reply_q: per IRQ's reply queue object. * - * Return: IRQ_HANDLED if processed, else IRQ_NONE. + * Return: number of reply descriptors processed from reply + * descriptor queue. */ -static irqreturn_t -_base_interrupt(int irq, void *bus_id) +static int +_base_process_reply_queue(struct adapter_reply_queue *reply_q) { - struct adapter_reply_queue *reply_q = bus_id; union reply_descriptor rd; - u32 completed_cmds; - u8 request_desript_type; + u64 completed_cmds; + u8 request_descript_type; u16 smid; u8 cb_idx; u32 reply; @@ -1404,21 +1439,18 @@ _base_interrupt(int irq, void *bus_id) Mpi2ReplyDescriptorsUnion_t *rpf; u8 rc; - if (ioc->mask_interrupts) - return IRQ_NONE; - + completed_cmds = 0; if (!atomic_add_unless(&reply_q->busy, 1, 1)) - return IRQ_NONE; + return completed_cmds; rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; - request_desript_type = rpf->Default.ReplyFlags + request_descript_type = rpf->Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { + if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { atomic_dec(&reply_q->busy); - return IRQ_NONE; + return completed_cmds; } - completed_cmds = 0; cb_idx = 0xFF; do { rd.word = le64_to_cpu(rpf->Words); @@ -1426,11 +1458,11 @@ _base_interrupt(int irq, void *bus_id) goto out; reply = 0; smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); - if (request_desript_type == + if (request_descript_type == MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS || - request_desript_type == + request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS || - request_desript_type == + request_descript_type == MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS) { cb_idx = _base_get_cb_idx(ioc, smid); if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && @@ -1440,7 +1472,7 @@ _base_interrupt(int irq, void *bus_id) if (rc) mpt3sas_base_free_smid(ioc, smid); } - } else if (request_desript_type == + } else if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { reply = le32_to_cpu( rpf->AddressReply.ReplyFrameAddress); @@ -1486,7 +1518,7 @@ _base_interrupt(int irq, void *bus_id) (reply_q->reply_post_host_index == (ioc->reply_post_queue_depth - 1)) ? 0 : reply_q->reply_post_host_index + 1; - request_desript_type = + request_descript_type = reply_q->reply_post_free[reply_q->reply_post_host_index]. Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; completed_cmds++; @@ -1495,7 +1527,7 @@ _base_interrupt(int irq, void *bus_id) * So that FW can find enough entries to post the Reply * Descriptors in the reply descriptor post queue. */ - if (completed_cmds > ioc->hba_queue_depth/3) { + if (!base_mod64(completed_cmds, ioc->thresh_hold)) { if (ioc->combined_reply_queue) { writel(reply_q->reply_post_host_index | ((msix_index & 7) << @@ -1507,9 +1539,14 @@ _base_interrupt(int irq, void *bus_id) MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); } - completed_cmds = 1; + if (!reply_q->irq_poll_scheduled) { + reply_q->irq_poll_scheduled = true; + irq_poll_sched(&reply_q->irqpoll); + } + atomic_dec(&reply_q->busy); + return completed_cmds; } - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) goto out; if (!reply_q->reply_post_host_index) rpf = reply_q->reply_post_free; @@ -1521,14 +1558,14 @@ _base_interrupt(int irq, void *bus_id) if (!completed_cmds) { atomic_dec(&reply_q->busy); - return IRQ_NONE; + return completed_cmds; } if (ioc->is_warpdrive) { writel(reply_q->reply_post_host_index, ioc->reply_post_host_index[msix_index]); atomic_dec(&reply_q->busy); - return IRQ_HANDLED; + return completed_cmds; } /* Update Reply Post Host Index. @@ -1555,7 +1592,82 @@ _base_interrupt(int irq, void *bus_id) MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); atomic_dec(&reply_q->busy); - return IRQ_HANDLED; + return completed_cmds; +} + +/** + * _base_interrupt - MPT adapter (IOC) specific interrupt handler. + * @irq: irq number (not used) + * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure + * + * Return: IRQ_HANDLED if processed, else IRQ_NONE. + */ +static irqreturn_t +_base_interrupt(int irq, void *bus_id) +{ + struct adapter_reply_queue *reply_q = bus_id; + struct MPT3SAS_ADAPTER *ioc = reply_q->ioc; + + if (ioc->mask_interrupts) + return IRQ_NONE; + if (reply_q->irq_poll_scheduled) + return IRQ_HANDLED; + return ((_base_process_reply_queue(reply_q) > 0) ? + IRQ_HANDLED : IRQ_NONE); +} + +/** + * _base_irqpoll - IRQ poll callback handler + * @irqpoll - irq_poll object + * @budget - irq poll weight + * + * returns number of reply descriptors processed + */ +static int +_base_irqpoll(struct irq_poll *irqpoll, int budget) +{ + struct adapter_reply_queue *reply_q; + int num_entries = 0; + + reply_q = container_of(irqpoll, struct adapter_reply_queue, + irqpoll); + if (reply_q->irq_line_enable) { + disable_irq(reply_q->os_irq); + reply_q->irq_line_enable = false; + } + num_entries = _base_process_reply_queue(reply_q); + if (num_entries < budget) { + irq_poll_complete(irqpoll); + reply_q->irq_poll_scheduled = false; + reply_q->irq_line_enable = true; + enable_irq(reply_q->os_irq); + } + + return num_entries; +} + +/** + * _base_init_irqpolls - initliaze IRQ polls + * @ioc: per adapter object + * + * returns nothing + */ +static void +_base_init_irqpolls(struct MPT3SAS_ADAPTER *ioc) +{ + struct adapter_reply_queue *reply_q, *next; + + if (list_empty(&ioc->reply_queue_list)) + return; + + list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { + irq_poll_init(&reply_q->irqpoll, + ioc->hba_queue_depth/4, _base_irqpoll); + reply_q->irq_poll_scheduled = false; + reply_q->irq_line_enable = true; + reply_q->os_irq = pci_irq_vector(ioc->pdev, + reply_q->msix_index); + } } /** @@ -1596,6 +1708,17 @@ mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc) /* TMs are on msix_index == 0 */ if (reply_q->msix_index == 0) continue; + if (reply_q->irq_poll_scheduled) { + /* Calling irq_poll_disable will wait for any pending + * callbacks to have completed. + */ + irq_poll_disable(&reply_q->irqpoll); + irq_poll_enable(&reply_q->irqpoll); + reply_q->irq_poll_scheduled = false; + reply_q->irq_line_enable = true; + enable_irq(reply_q->os_irq); + continue; + } synchronize_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index)); } } @@ -2690,6 +2813,9 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc) list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { list_del(&reply_q->list); + if (ioc->smp_affinity_enable) + irq_set_affinity_hint(pci_irq_vector(ioc->pdev, + reply_q->msix_index), NULL); free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index), reply_q); kfree(reply_q); @@ -2754,10 +2880,14 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) { unsigned int cpu, nr_cpus, nr_msix, index = 0; struct adapter_reply_queue *reply_q; + int local_numa_node; if (!_base_is_controller_msix_enabled(ioc)) return; + if (ioc->msix_load_balance) + return; + memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); nr_cpus = num_online_cpus(); @@ -2766,14 +2896,33 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) if (!nr_msix) return; - if (smp_affinity_enable) { + if (ioc->smp_affinity_enable) { + + /* + * set irq affinity to local numa node for those irqs + * corresponding to high iops queues. + */ + if (ioc->high_iops_queues) { + local_numa_node = dev_to_node(&ioc->pdev->dev); + for (index = 0; index < ioc->high_iops_queues; + index++) { + irq_set_affinity_hint(pci_irq_vector(ioc->pdev, + index), cpumask_of_node(local_numa_node)); + } + } + list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev, - reply_q->msix_index); + const cpumask_t *mask; + + if (reply_q->msix_index < ioc->high_iops_queues) + continue; + + mask = pci_irq_get_affinity(ioc->pdev, + reply_q->msix_index); if (!mask) { ioc_warn(ioc, "no affinity for msi %x\n", reply_q->msix_index); - continue; + goto fall_back; } for_each_cpu_and(cpu, mask, cpu_online_mask) { @@ -2784,12 +2933,18 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) } return; } + +fall_back: cpu = cpumask_first(cpu_online_mask); + nr_msix -= ioc->high_iops_queues; + index = 0; list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - unsigned int i, group = nr_cpus / nr_msix; + if (reply_q->msix_index < ioc->high_iops_queues) + continue; + if (cpu >= nr_cpus) break; @@ -2805,6 +2960,52 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) } /** + * _base_check_and_enable_high_iops_queues - enable high iops mode + * @ ioc - per adapter object + * @ hba_msix_vector_count - msix vectors supported by HBA + * + * Enable high iops queues only if + * - HBA is a SEA/AERO controller and + * - MSI-Xs vector supported by the HBA is 128 and + * - total CPU count in the system >=16 and + * - loaded driver with default max_msix_vectors module parameter and + * - system booted in non kdump mode + * + * returns nothing. + */ +static void +_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, + int hba_msix_vector_count) +{ + u16 lnksta, speed; + + if (perf_mode == MPT_PERF_MODE_IOPS || + perf_mode == MPT_PERF_MODE_LATENCY) { + ioc->high_iops_queues = 0; + return; + } + + if (perf_mode == MPT_PERF_MODE_DEFAULT) { + + pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta); + speed = lnksta & PCI_EXP_LNKSTA_CLS; + + if (speed < 0x4) { + ioc->high_iops_queues = 0; + return; + } + } + + if (!reset_devices && ioc->is_aero_ioc && + hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES && + num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES && + max_msix_vectors == -1) + ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES; + else + ioc->high_iops_queues = 0; +} + +/** * _base_disable_msix - disables msix * @ioc: per adapter object * @@ -2814,11 +3015,38 @@ _base_disable_msix(struct MPT3SAS_ADAPTER *ioc) { if (!ioc->msix_enable) return; - pci_disable_msix(ioc->pdev); + pci_free_irq_vectors(ioc->pdev); ioc->msix_enable = 0; } /** + * _base_alloc_irq_vectors - allocate msix vectors + * @ioc: per adapter object + * + */ +static int +_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc) +{ + int i, irq_flags = PCI_IRQ_MSIX; + struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues }; + struct irq_affinity *descp = &desc; + + if (ioc->smp_affinity_enable) + irq_flags |= PCI_IRQ_AFFINITY; + else + descp = NULL; + + ioc_info(ioc, " %d %d\n", ioc->high_iops_queues, + ioc->msix_vector_count); + + i = pci_alloc_irq_vectors_affinity(ioc->pdev, + ioc->high_iops_queues, + ioc->msix_vector_count, irq_flags, descp); + + return i; +} + +/** * _base_enable_msix - enables msix, failback to io_apic * @ioc: per adapter object * @@ -2829,7 +3057,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) int r; int i, local_max_msix_vectors; u8 try_msix = 0; - unsigned int irq_flags = PCI_IRQ_MSIX; + + ioc->msix_load_balance = false; if (msix_disable == -1 || msix_disable == 0) try_msix = 1; @@ -2840,12 +3069,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) if (_base_check_enable_msix(ioc) != 0) goto try_ioapic; - ioc->reply_queue_count = min_t(int, ioc->cpu_count, + ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count); + pr_info("\t no of cores: %d, max_msix_vectors: %d\n", + ioc->cpu_count, max_msix_vectors); + if (ioc->is_aero_ioc) + _base_check_and_enable_high_iops_queues(ioc, + ioc->msix_vector_count); + ioc->reply_queue_count = + min_t(int, ioc->cpu_count + ioc->high_iops_queues, ioc->msix_vector_count); - ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n", - ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors); - if (!ioc->rdpq_array_enable && max_msix_vectors == -1) local_max_msix_vectors = (reset_devices) ? 1 : 8; else @@ -2857,14 +3090,23 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) else if (local_max_msix_vectors == 0) goto try_ioapic; - if (ioc->msix_vector_count < ioc->cpu_count) - smp_affinity_enable = 0; + /* + * Enable msix_load_balance only if combined reply queue mode is + * disabled on SAS3 & above generation HBA devices. + */ + if (!ioc->combined_reply_queue && + ioc->hba_mpi_version_belonged != MPI2_VERSION) { + ioc->msix_load_balance = true; + } - if (smp_affinity_enable) - irq_flags |= PCI_IRQ_AFFINITY; + /* + * smp affinity setting is not need when msix load balance + * is enabled. + */ + if (ioc->msix_load_balance) + ioc->smp_affinity_enable = 0; - r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count, - irq_flags); + r = _base_alloc_irq_vectors(ioc); if (r < 0) { dfailprintk(ioc, ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n", @@ -2883,11 +3125,15 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) } } + ioc_info(ioc, "High IOPs queues : %s\n", + ioc->high_iops_queues ? "enabled" : "disabled"); + return 0; /* failback to io_apic interrupt routing */ try_ioapic: - + ioc->high_iops_queues = 0; + ioc_info(ioc, "High IOPs queues : disabled\n"); ioc->reply_queue_count = 1; r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY); if (r < 0) { @@ -3015,6 +3261,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_fail; + if (!ioc->is_driver_loading) + _base_init_irqpolls(ioc); /* Use the Combined reply queue feature only for SAS3 C0 & higher * revision HBAs and also only when reply queue count is greater than 8 */ @@ -3155,13 +3403,58 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr) return ioc->reply + (phys_addr - (u32)ioc->reply_dma); } +/** + * _base_get_msix_index - get the msix index + * @ioc: per adapter object + * @scmd: scsi_cmnd object + * + * returns msix index of general reply queues, + * i.e. reply queue on which IO request's reply + * should be posted by the HBA firmware. + */ static inline u8 -_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc) +_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd) { + /* Enables reply_queue load balancing */ + if (ioc->msix_load_balance) + return ioc->reply_queue_count ? + base_mod64(atomic64_add_return(1, + &ioc->total_io_cnt), ioc->reply_queue_count) : 0; + return ioc->cpu_msix_table[raw_smp_processor_id()]; } /** + * _base_get_high_iops_msix_index - get the msix index of + * high iops queues + * @ioc: per adapter object + * @scmd: scsi_cmnd object + * + * Returns: msix index of high iops reply queues. + * i.e. high iops reply queue on which IO request's + * reply should be posted by the HBA firmware. + */ +static inline u8 +_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd) +{ + /** + * Round robin the IO interrupts among the high iops + * reply queues in terms of batch count 16 when outstanding + * IOs on the target device is >=8. + */ + if (atomic_read(&scmd->device->device_busy) > + MPT3SAS_DEVICE_HIGH_IOPS_DEPTH) + return base_mod64(( + atomic64_add_return(1, &ioc->high_iops_outstanding) / + MPT3SAS_HIGH_IOPS_BATCH_COUNT), + MPT3SAS_HIGH_IOPS_REPLY_QUEUES); + + return _base_get_msix_index(ioc, scmd); +} + +/** * mpt3sas_base_get_smid - obtain a free smid from internal queue * @ioc: per adapter object * @cb_idx: callback index @@ -3209,8 +3502,8 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, smid = tag + 1; request->cb_idx = cb_idx; - request->msix_io = _base_get_msix_index(ioc); request->smid = smid; + request->scmd = scmd; INIT_LIST_HEAD(&request->chain_list); return smid; } @@ -3264,6 +3557,7 @@ void mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc, return; st->cb_idx = 0xFF; st->direct_io = 0; + st->scmd = NULL; atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0); st->smid = 0; } @@ -3333,7 +3627,6 @@ _base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr, spin_lock_irqsave(writeq_lock, flags); __raw_writel((u32)(b), addr); __raw_writel((u32)(b >> 32), (addr + 4)); - mmiowb(); spin_unlock_irqrestore(writeq_lock, flags); } @@ -3364,13 +3657,37 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) #endif /** + * _base_set_and_get_msix_index - get the msix index and assign to msix_io + * variable of scsi tracker + * @ioc: per adapter object + * @smid: system request message index + * + * returns msix index. + */ +static u8 +_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + struct scsiio_tracker *st = NULL; + + if (smid < ioc->hi_priority_smid) + st = _get_st_from_smid(ioc, smid); + + if (st == NULL) + return _base_get_msix_index(ioc, NULL); + + st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd); + return st->msix_io; +} + +/** * _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 */ static void -_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) +_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, + u16 smid, u16 handle) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; @@ -3383,7 +3700,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) _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.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3405,7 +3722,7 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3414,13 +3731,13 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) } /** - * mpt3sas_base_put_smid_fast_path - send fast path request to firmware + * _base_put_smid_fast_path - send fast path request to firmware * @ioc: per adapter object * @smid: system request message index * @handle: device handle */ -void -mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, +static void +_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) { Mpi2RequestDescriptorUnion_t descriptor; @@ -3428,7 +3745,7 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, descriptor.SCSIIO.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3437,13 +3754,13 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, } /** - * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware + * _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. */ -void -mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, +static void +_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 msix_task) { Mpi2RequestDescriptorUnion_t descriptor; @@ -3492,7 +3809,7 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) descriptor.Default.RequestFlags = MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); + descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -3501,12 +3818,12 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** - * mpt3sas_base_put_smid_default - Default, primarily used for config pages + * _base_put_smid_default - Default, primarily used for config pages * @ioc: per adapter object * @smid: system request message index */ -void -mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) +static void +_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) { Mpi2RequestDescriptorUnion_t descriptor; void *mpi_req_iomem; @@ -3524,7 +3841,7 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) } request = (u64 *)&descriptor; descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); + descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -3538,6 +3855,95 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** + * _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_set_and_get_msix_index(ioc, smid); + 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_set_and_get_msix_index(ioc, smid); + 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_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_set_and_get_msix_index(ioc, smid); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** * _base_display_OEMs_branding - Display branding string * @ioc: per adapter object */ @@ -3837,7 +4243,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma, data_length); init_completion(&ioc->base_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); /* Wait for 15 seconds */ wait_for_completion_timeout(&ioc->base_cmds.done, FW_IMG_HDR_READ_TIMEOUT*HZ); @@ -4077,6 +4483,71 @@ out: } /** + * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields + * according to performance mode. + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi2IOCPage1_t ioc_pg1; + Mpi2ConfigReply_t mpi_reply; + + mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy); + memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t)); + + switch (perf_mode) { + case MPT_PERF_MODE_DEFAULT: + case MPT_PERF_MODE_BALANCED: + if (ioc->high_iops_queues) { + ioc_info(ioc, + "Enable interrupt coalescing only for first\t" + "%d reply queues\n", + MPT3SAS_HIGH_IOPS_REPLY_QUEUES); + /* + * If 31st bit is zero then interrupt coalescing is + * enabled for all reply descriptor post queues. + * If 31st bit is set to one then user can + * enable/disable interrupt coalescing on per reply + * descriptor post queue group(8) basis. So to enable + * interrupt coalescing only on first reply descriptor + * post queue group 31st bit and zero th bit is enabled. + */ + ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 | + ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1)); + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + ioc_info(ioc, "performance mode: balanced\n"); + return; + } + /* Fall through */ + case MPT_PERF_MODE_LATENCY: + /* + * Enable interrupt coalescing on all reply queues + * with timeout value 0xA + */ + ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa); + ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING); + ioc_pg1.ProductSpecific = 0; + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + ioc_info(ioc, "performance mode: latency\n"); + break; + case MPT_PERF_MODE_IOPS: + /* + * Enable interrupt coalescing on all reply queues. + */ + ioc_info(ioc, + "performance mode: iops with coalescing timeout: 0x%x\n", + le32_to_cpu(ioc_pg1.CoalescingTimeout)); + ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING); + ioc_pg1.ProductSpecific = 0; + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + break; + } +} + +/** * _base_static_config_pages - static start of day config pages * @ioc: per adapter object */ @@ -4143,6 +4614,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) if (ioc->iounit_pg8.NumSensors) ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; + if (ioc->is_aero_ioc) + _base_update_ioc_page1_inlinewith_perf_mode(ioc); } /** @@ -5316,7 +5789,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->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 || @@ -5395,7 +5868,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->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)) { @@ -5578,6 +6051,9 @@ _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->is_aero_ioc) + ioc->atomic_desc_capable = 1; facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); facts->IOCRequestFrameSize = le16_to_cpu(mpi_reply.IOCRequestFrameSize); @@ -5799,7 +6275,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; init_completion(&ioc->port_enable_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->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)) { ioc_err(ioc, "%s: timeout\n", __func__); @@ -5858,7 +6334,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc) memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); return 0; } @@ -5974,7 +6450,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { ioc_err(ioc, "%s: timeout\n", __func__); @@ -6434,6 +6910,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) } } + ioc->smp_affinity_enable = smp_affinity_enable; + ioc->rdpq_array_enable_assigned = 0; ioc->dma_mask = 0; if (ioc->is_aero_ioc) @@ -6454,6 +6932,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->build_sg_scmd = &_base_build_sg_scmd; ioc->build_sg = &_base_build_sg; ioc->build_zero_len_sge = &_base_build_zero_len_sge; + ioc->get_msix_index_for_smlio = &_base_get_msix_index; break; case MPI25_VERSION: case MPI26_VERSION: @@ -6468,15 +6947,30 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->build_nvme_prp = &_base_build_nvme_prp; ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); - + if (ioc->high_iops_queues) + ioc->get_msix_index_for_smlio = + &_base_get_high_iops_msix_index; + else + ioc->get_msix_index_for_smlio = &_base_get_msix_index; break; } - - 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; - + 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; + } else { + ioc->put_smid_default = &_base_put_smid_default; + ioc->put_smid_fast_path = &_base_put_smid_fast_path; + ioc->put_smid_hi_priority = &_base_put_smid_hi_priority; + 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; + } /* * These function pointers for other requests that don't * the require IEEE scatter gather elements. @@ -6507,6 +7001,12 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; + if (irqpoll_weight > 0) + ioc->thresh_hold = irqpoll_weight; + else + ioc->thresh_hold = ioc->hba_queue_depth/4; + + _base_init_irqpolls(ioc); init_waitqueue_head(&ioc->reset_wq); /* allocate memory pd handle bitmask list */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 19158cb59101..6afbdb044310 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -67,6 +67,7 @@ #include <scsi/scsi_eh.h> #include <linux/pci.h> #include <linux/poll.h> +#include <linux/irq_poll.h> #include "mpt3sas_debug.h" #include "mpt3sas_trigger_diag.h" @@ -75,9 +76,9 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "27.102.00.00" -#define MPT3SAS_MAJOR_VERSION 27 -#define MPT3SAS_MINOR_VERSION 102 +#define MPT3SAS_DRIVER_VERSION "29.100.00.00" +#define MPT3SAS_MAJOR_VERSION 29 +#define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 @@ -354,6 +355,12 @@ struct mpt3sas_nvme_cmd { #define VIRTUAL_IO_FAILED_RETRY (0x32010081) +/* High IOPs definitions */ +#define MPT3SAS_DEVICE_HIGH_IOPS_DEPTH 8 +#define MPT3SAS_HIGH_IOPS_REPLY_QUEUES 8 +#define MPT3SAS_HIGH_IOPS_BATCH_COUNT 16 +#define MPT3SAS_GEN35_MAX_MSIX_QUEUES 128 + /* OEM Specific Flags will come from OEM specific header files */ struct Mpi2ManufacturingPage10_t { MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ @@ -823,6 +830,7 @@ struct chain_lookup { */ struct scsiio_tracker { u16 smid; + struct scsi_cmnd *scmd; u8 cb_idx; u8 direct_io; struct pcie_sg_list pcie_sg_list; @@ -882,6 +890,9 @@ struct _event_ack_list { * @reply_post_free: reply post base virt address * @name: the name registered to request_irq() * @busy: isr is actively processing replies on another cpu + * @os_irq: irq number + * @irqpoll: irq_poll object + * @irq_poll_scheduled: Tells whether irq poll is scheduled or not * @list: this list */ struct adapter_reply_queue { @@ -891,6 +902,10 @@ struct adapter_reply_queue { Mpi2ReplyDescriptorsUnion_t *reply_post_free; char name[MPT_NAME_LENGTH]; atomic_t busy; + u32 os_irq; + struct irq_poll irqpoll; + bool irq_poll_scheduled; + bool irq_line_enable; struct list_head list; }; @@ -916,6 +931,12 @@ typedef void (*PUT_SMID_IO_FP_HIP) (struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 funcdep); typedef void (*PUT_SMID_DEFAULT) (struct MPT3SAS_ADAPTER *ioc, u16 smid); typedef u32 (*BASE_READ_REG) (const volatile void __iomem *addr); +/* + * To get high iops reply queue's msix index when high iops mode is enabled + * else get the msix index of general reply queues. + */ +typedef u8 (*GET_MSIX_INDEX) (struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd); /* IOC Facts and Port Facts converted from little endian to cpu */ union mpi3_version_union { @@ -1016,7 +1037,14 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @msix_vector_count: number msix vectors * @cpu_msix_table: table for mapping cpus to msix index * @cpu_msix_table_sz: table size + * @total_io_cnt: Gives total IO count, used to load balance the interrupts + * @high_iops_outstanding: used to load balance the interrupts + * within high iops reply queues + * @msix_load_balance: Enables load balancing of interrupts across + * the multiple MSIXs * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands + * @thresh_hold: Max number of reply descriptors processed + * before updating Host Index * @scsi_io_cb_idx: shost generated commands * @tm_cb_idx: task management commands * @scsih_cb_idx: scsih internal commands @@ -1134,6 +1162,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * path functions resulting in Null pointer reference followed by kernel * crash. To avoid the above race condition we use mutex syncrhonization * which ensures the syncrhonization between cli/sysfs_show path. + * @atomic_desc_capable: Atomic Request Descriptor support. + * @GET_MSIX_INDEX: Get the msix index of high iops queues. */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -1192,6 +1222,11 @@ struct MPT3SAS_ADAPTER { u32 ioc_reset_count; MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; u32 non_operational_loop; + atomic64_t total_io_cnt; + atomic64_t high_iops_outstanding; + bool msix_load_balance; + u16 thresh_hold; + u8 high_iops_queues; /* internal commands, callback index */ u8 scsi_io_cb_idx; @@ -1251,6 +1286,7 @@ struct MPT3SAS_ADAPTER { Mpi2IOUnitPage0_t iounit_pg0; Mpi2IOUnitPage1_t iounit_pg1; Mpi2IOUnitPage8_t iounit_pg8; + Mpi2IOCPage1_t ioc_pg1_copy; struct _boot_device req_boot_device; struct _boot_device req_alt_boot_device; @@ -1369,6 +1405,7 @@ struct MPT3SAS_ADAPTER { u8 combined_reply_queue; u8 combined_reply_index_count; + u8 smp_affinity_enable; /* reply post register index */ resource_size_t **replyPostRegisterIndex; @@ -1396,6 +1433,7 @@ struct MPT3SAS_ADAPTER { u8 hide_drives; spinlock_t diag_trigger_lock; u8 diag_trigger_active; + u8 atomic_desc_capable; BASE_READ_REG base_readl; struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event; @@ -1406,7 +1444,10 @@ struct MPT3SAS_ADAPTER { u8 is_gen35_ioc; u8 is_aero_ioc; 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; + GET_MSIX_INDEX get_msix_index_for_smlio; }; typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -1595,6 +1636,10 @@ int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, int mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); +int mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOCPage1_t *config_page); +int mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOCPage1_t *config_page); int mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page); int mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index fb0a17252f86..14a1a2793dd5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -380,7 +380,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ); if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) { mpt3sas_base_check_cmd_timeout(ioc, @@ -949,6 +949,77 @@ mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, out: return r; } +/** + * mpt3sas_config_get_ioc_pg1 - obtain ioc page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Return: 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_ioc_pg1 - modify ioc page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Return: 0 for success, non-zero for failure. + */ +int +mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} /** * mpt3sas_config_get_sas_device_pg0 - obtain sas device page 0 diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index b2bb47c14d35..d4ecfbbe738c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -822,7 +822,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 - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -859,7 +859,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); - mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); + ioc->put_smid_hi_priority(ioc, smid, 0); break; } case MPI2_FUNCTION_SMP_PASSTHROUGH: @@ -890,7 +890,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SATA_PASSTHROUGH: @@ -905,7 +905,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_FW_DOWNLOAD: @@ -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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_TOOLBOX: @@ -928,7 +928,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); } - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: @@ -948,7 +948,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); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } @@ -1576,7 +1576,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, cpu_to_le32(ioc->product_specific[buffer_type][i]); init_completion(&ioc->ctl_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1903,7 +1903,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, mpi_request->VP_ID = 0; init_completion(&ioc->ctl_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2151,7 +2151,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) mpi_request->VP_ID = 0; init_completion(&ioc->ctl_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2319,6 +2319,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, break; } + if (karg.hdr.ioc_number != ioctl_header.ioc_number) { + ret = -EINVAL; + break; + } if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) { uarg = arg; ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); @@ -2453,7 +2457,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) /* scsi host attributes */ /** - * _ctl_version_fw_show - firmware version + * version_fw_show - firmware version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2461,7 +2465,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, +version_fw_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2473,10 +2477,10 @@ _ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, ioc->facts.FWVersion.Word & 0x000000FF); } -static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); +static DEVICE_ATTR_RO(version_fw); /** - * _ctl_version_bios_show - bios version + * version_bios_show - bios version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2484,7 +2488,7 @@ static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, +version_bios_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2498,10 +2502,10 @@ _ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, (version & 0x0000FF00) >> 8, version & 0x000000FF); } -static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); +static DEVICE_ATTR_RO(version_bios); /** - * _ctl_version_mpi_show - MPI (message passing interface) version + * version_mpi_show - MPI (message passing interface) version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2509,7 +2513,7 @@ static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, +version_mpi_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2518,10 +2522,10 @@ _ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); } -static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); +static DEVICE_ATTR_RO(version_mpi); /** - * _ctl_version_product_show - product name + * version_product_show - product name * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2529,7 +2533,7 @@ static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, +version_product_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2537,10 +2541,10 @@ _ctl_version_product_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); } -static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL); +static DEVICE_ATTR_RO(version_product); /** - * _ctl_version_nvdata_persistent_show - ndvata persistent version + * version_nvdata_persistent_show - ndvata persistent version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2548,7 +2552,7 @@ static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_nvdata_persistent_show(struct device *cdev, +version_nvdata_persistent_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2557,11 +2561,10 @@ _ctl_version_nvdata_persistent_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%08xh\n", le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); } -static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, - _ctl_version_nvdata_persistent_show, NULL); +static DEVICE_ATTR_RO(version_nvdata_persistent); /** - * _ctl_version_nvdata_default_show - nvdata default version + * version_nvdata_default_show - nvdata default version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2569,7 +2572,7 @@ static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute +version_nvdata_default_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2578,11 +2581,10 @@ _ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute return snprintf(buf, PAGE_SIZE, "%08xh\n", le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); } -static DEVICE_ATTR(version_nvdata_default, S_IRUGO, - _ctl_version_nvdata_default_show, NULL); +static DEVICE_ATTR_RO(version_nvdata_default); /** - * _ctl_board_name_show - board name + * board_name_show - board name * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2590,7 +2592,7 @@ static DEVICE_ATTR(version_nvdata_default, S_IRUGO, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, +board_name_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2598,10 +2600,10 @@ _ctl_board_name_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); } -static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); +static DEVICE_ATTR_RO(board_name); /** - * _ctl_board_assembly_show - board assembly name + * board_assembly_show - board assembly name * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2609,7 +2611,7 @@ static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, +board_assembly_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2617,10 +2619,10 @@ _ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); } -static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL); +static DEVICE_ATTR_RO(board_assembly); /** - * _ctl_board_tracer_show - board tracer number + * board_tracer_show - board tracer number * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2628,7 +2630,7 @@ static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, +board_tracer_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2636,10 +2638,10 @@ _ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); } -static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL); +static DEVICE_ATTR_RO(board_tracer); /** - * _ctl_io_delay_show - io missing delay + * io_delay_show - io missing delay * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2650,7 +2652,7 @@ static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, +io_delay_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2658,10 +2660,10 @@ _ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); } -static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL); +static DEVICE_ATTR_RO(io_delay); /** - * _ctl_device_delay_show - device missing delay + * device_delay_show - device missing delay * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2672,7 +2674,7 @@ static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, +device_delay_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2680,10 +2682,10 @@ _ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); } -static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL); +static DEVICE_ATTR_RO(device_delay); /** - * _ctl_fw_queue_depth_show - global credits + * fw_queue_depth_show - global credits * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2693,7 +2695,7 @@ static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, +fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2701,10 +2703,10 @@ _ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); } -static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL); +static DEVICE_ATTR_RO(fw_queue_depth); /** - * _ctl_sas_address_show - sas address + * sas_address_show - sas address * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2714,7 +2716,7 @@ static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, +host_sas_address_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -2724,11 +2726,10 @@ _ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "0x%016llx\n", (unsigned long long)ioc->sas_hba.sas_address); } -static DEVICE_ATTR(host_sas_address, S_IRUGO, - _ctl_host_sas_address_show, NULL); +static DEVICE_ATTR_RO(host_sas_address); /** - * _ctl_logging_level_show - logging level + * logging_level_show - logging level * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2736,7 +2737,7 @@ static DEVICE_ATTR(host_sas_address, S_IRUGO, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, +logging_level_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2745,7 +2746,7 @@ _ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); } static ssize_t -_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, +logging_level_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2760,11 +2761,10 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, ioc->logging_level); return strlen(buf); } -static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, - _ctl_logging_level_store); +static DEVICE_ATTR_RW(logging_level); /** - * _ctl_fwfault_debug_show - show/store fwfault_debug + * fwfault_debug_show - show/store fwfault_debug * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2773,7 +2773,7 @@ static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr, +fwfault_debug_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2782,7 +2782,7 @@ _ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); } static ssize_t -_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, +fwfault_debug_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2797,11 +2797,10 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, ioc->fwfault_debug); return strlen(buf); } -static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, - _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); +static DEVICE_ATTR_RW(fwfault_debug); /** - * _ctl_ioc_reset_count_show - ioc reset count + * ioc_reset_count_show - ioc reset count * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2811,7 +2810,7 @@ static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, +ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2819,10 +2818,10 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count); } -static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); +static DEVICE_ATTR_RO(ioc_reset_count); /** - * _ctl_ioc_reply_queue_count_show - number of reply queues + * reply_queue_count_show - number of reply queues * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2832,7 +2831,7 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_ioc_reply_queue_count_show(struct device *cdev, +reply_queue_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { u8 reply_queue_count; @@ -2847,11 +2846,10 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); } -static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, - NULL); +static DEVICE_ATTR_RO(reply_queue_count); /** - * _ctl_BRM_status_show - Backup Rail Monitor Status + * BRM_status_show - Backup Rail Monitor Status * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2861,7 +2859,7 @@ static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, +BRM_status_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2923,7 +2921,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, mutex_unlock(&ioc->pci_access_mutex); return rc; } -static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); +static DEVICE_ATTR_RO(BRM_status); struct DIAG_BUFFER_START { __le32 Size; @@ -2936,7 +2934,7 @@ struct DIAG_BUFFER_START { }; /** - * _ctl_host_trace_buffer_size_show - host buffer size (trace only) + * host_trace_buffer_size_show - host buffer size (trace only) * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2944,7 +2942,7 @@ struct DIAG_BUFFER_START { * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_host_trace_buffer_size_show(struct device *cdev, +host_trace_buffer_size_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2976,11 +2974,10 @@ _ctl_host_trace_buffer_size_show(struct device *cdev, ioc->ring_buffer_sz = size; return snprintf(buf, PAGE_SIZE, "%d\n", size); } -static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, - _ctl_host_trace_buffer_size_show, NULL); +static DEVICE_ATTR_RO(host_trace_buffer_size); /** - * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) + * host_trace_buffer_show - firmware ring buffer (trace only) * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2992,7 +2989,7 @@ static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, * offset to the same attribute, it will move the pointer. */ static ssize_t -_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, +host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3024,7 +3021,7 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, } static ssize_t -_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, +host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3037,14 +3034,13 @@ _ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, ioc->ring_buffer_offset = val; return strlen(buf); } -static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); +static DEVICE_ATTR_RW(host_trace_buffer); /*****************************************/ /** - * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) + * host_trace_buffer_enable_show - firmware ring buffer (trace only) * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3054,7 +3050,7 @@ static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, * This is a mechnism to post/release host_trace_buffers */ static ssize_t -_ctl_host_trace_buffer_enable_show(struct device *cdev, +host_trace_buffer_enable_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3072,7 +3068,7 @@ _ctl_host_trace_buffer_enable_show(struct device *cdev, } static ssize_t -_ctl_host_trace_buffer_enable_store(struct device *cdev, +host_trace_buffer_enable_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3122,14 +3118,12 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev, out: return strlen(buf); } -static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_enable_show, - _ctl_host_trace_buffer_enable_store); +static DEVICE_ATTR_RW(host_trace_buffer_enable); /*********** diagnostic trigger suppport *********************************/ /** - * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute + * diag_trigger_master_show - show the diag_trigger_master attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3137,7 +3131,7 @@ static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_master_show(struct device *cdev, +diag_trigger_master_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -3154,7 +3148,7 @@ _ctl_diag_trigger_master_show(struct device *cdev, } /** - * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute + * diag_trigger_master_store - store the diag_trigger_master attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3163,7 +3157,7 @@ _ctl_diag_trigger_master_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_master_store(struct device *cdev, +diag_trigger_master_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -3182,12 +3176,11 @@ _ctl_diag_trigger_master_store(struct device *cdev, spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); return rc; } -static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store); +static DEVICE_ATTR_RW(diag_trigger_master); /** - * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute + * diag_trigger_event_show - show the diag_trigger_event attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3195,7 +3188,7 @@ static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_event_show(struct device *cdev, +diag_trigger_event_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3211,7 +3204,7 @@ _ctl_diag_trigger_event_show(struct device *cdev, } /** - * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute + * diag_trigger_event_store - store the diag_trigger_event attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3220,7 +3213,7 @@ _ctl_diag_trigger_event_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_event_store(struct device *cdev, +diag_trigger_event_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -3239,12 +3232,11 @@ _ctl_diag_trigger_event_store(struct device *cdev, spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); return sz; } -static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store); +static DEVICE_ATTR_RW(diag_trigger_event); /** - * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute + * diag_trigger_scsi_show - show the diag_trigger_scsi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3252,7 +3244,7 @@ static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_scsi_show(struct device *cdev, +diag_trigger_scsi_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3268,7 +3260,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev, } /** - * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute + * diag_trigger_scsi_store - store the diag_trigger_scsi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3277,7 +3269,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_scsi_store(struct device *cdev, +diag_trigger_scsi_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3295,12 +3287,11 @@ _ctl_diag_trigger_scsi_store(struct device *cdev, spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); return sz; } -static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store); +static DEVICE_ATTR_RW(diag_trigger_scsi); /** - * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute + * diag_trigger_scsi_show - show the diag_trigger_mpi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3308,7 +3299,7 @@ static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_mpi_show(struct device *cdev, +diag_trigger_mpi_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3324,7 +3315,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev, } /** - * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute + * diag_trigger_mpi_store - store the diag_trigger_mpi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3333,7 +3324,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_mpi_store(struct device *cdev, +diag_trigger_mpi_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3352,8 +3343,7 @@ _ctl_diag_trigger_mpi_store(struct device *cdev, return sz; } -static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store); +static DEVICE_ATTR_RW(diag_trigger_mpi); /*********** diagnostic trigger suppport *** END ****************************/ @@ -3391,7 +3381,7 @@ struct device_attribute *mpt3sas_host_attrs[] = { /* device attributes */ /** - * _ctl_device_sas_address_show - sas address + * sas_address_show - sas address * @dev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3401,7 +3391,7 @@ struct device_attribute *mpt3sas_host_attrs[] = { * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, +sas_address_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -3410,10 +3400,10 @@ _ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "0x%016llx\n", (unsigned long long)sas_device_priv_data->sas_target->sas_address); } -static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); +static DEVICE_ATTR_RO(sas_address); /** - * _ctl_device_handle_show - device handle + * sas_device_handle_show - device handle * @dev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3423,7 +3413,7 @@ static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, +sas_device_handle_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -3432,10 +3422,10 @@ _ctl_device_handle_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "0x%04x\n", sas_device_priv_data->sas_target->handle); } -static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); +static DEVICE_ATTR_RO(sas_device_handle); /** - * _ctl_device_ncq_io_prio_show - send prioritized io commands to device + * sas_ncq_io_prio_show - send prioritized io commands to device * @dev: pointer to embedded device * @attr: ? * @buf: the buffer returned @@ -3443,7 +3433,7 @@ static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); * A sysfs 'read/write' sdev attribute, only works with SATA */ static ssize_t -_ctl_device_ncq_prio_enable_show(struct device *dev, +sas_ncq_prio_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -3454,7 +3444,7 @@ _ctl_device_ncq_prio_enable_show(struct device *dev, } static ssize_t -_ctl_device_ncq_prio_enable_store(struct device *dev, +sas_ncq_prio_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -3471,9 +3461,7 @@ _ctl_device_ncq_prio_enable_store(struct device *dev, sas_device_priv_data->ncq_prio_enable = ncq_prio_enable; return strlen(buf); } -static DEVICE_ATTR(sas_ncq_prio_enable, S_IRUGO | S_IWUSR, - _ctl_device_ncq_prio_enable_show, - _ctl_device_ncq_prio_enable_store); +static DEVICE_ATTR_RW(sas_ncq_prio_enable); struct device_attribute *mpt3sas_dev_attrs[] = { &dev_attr_sas_address, diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 1ccfbc7eebe0..27c731a3fb49 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -113,22 +113,22 @@ MODULE_PARM_DESC(logging_level, static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); +module_param(max_sectors, ushort, 0444); MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); static int missing_delay[2] = {-1, -1}; -module_param_array(missing_delay, int, NULL, 0); +module_param_array(missing_delay, int, NULL, 0444); MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPT3SAS_MAX_LUN (16895) static u64 max_lun = MPT3SAS_MAX_LUN; -module_param(max_lun, ullong, 0); +module_param(max_lun, ullong, 0444); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); static ushort hbas_to_enumerate; -module_param(hbas_to_enumerate, ushort, 0); +module_param(hbas_to_enumerate, ushort, 0444); MODULE_PARM_DESC(hbas_to_enumerate, " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \ 1 - enumerates only SAS 2.0 generation HBAs\n \ @@ -142,17 +142,17 @@ MODULE_PARM_DESC(hbas_to_enumerate, * Either bit can be set, or both */ static int diag_buffer_enable = -1; -module_param(diag_buffer_enable, int, 0); +module_param(diag_buffer_enable, int, 0444); MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); static int disable_discovery = -1; -module_param(disable_discovery, int, 0); +module_param(disable_discovery, int, 0444); MODULE_PARM_DESC(disable_discovery, " disable discovery "); /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ static int prot_mask = -1; -module_param(prot_mask, int, 0); +module_param(prot_mask, int, 0444); MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); @@ -2685,7 +2685,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun, int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); mpt3sas_scsih_set_tm_flag(ioc, handle); init_completion(&ioc->tm_cmds.done); - mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task); + ioc->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)) { if (mpt3sas_base_check_cmd_timeout(ioc, @@ -3659,7 +3659,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; mpi_request->MsgFlags = tr_method; set_bit(handle, ioc->device_remove_in_progress); - mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); + ioc->put_smid_hi_priority(ioc, smid, 0); mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); out: @@ -3755,7 +3755,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; - mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl); + ioc->put_smid_default(ioc, smid_sas_ctrl); return _scsih_check_for_pending_tm(ioc, smid); } @@ -3881,7 +3881,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; - mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); + ioc->put_smid_hi_priority(ioc, smid, 0); } /** @@ -3970,7 +3970,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; - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); } /** @@ -4026,7 +4026,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 = cpu_to_le16(handle); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); } /** @@ -4734,12 +4734,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); - mpt3sas_base_put_smid_fast_path(ioc, smid, handle); + ioc->put_smid_fast_path(ioc, smid, handle); } else ioc->put_smid_scsi_io(ioc, smid, le16_to_cpu(mpi_request->DevHandle)); } else - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); return 0; out: @@ -5210,6 +5210,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) ((ioc_status & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { st->direct_io = 0; + st->scmd = scmd; memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); mpi_request->DevHandle = cpu_to_le16(sas_device_priv_data->sas_target->handle); @@ -7601,7 +7602,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) handle, phys_disk_num)); init_completion(&ioc->scsih_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { @@ -9633,7 +9634,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) if (!ioc->hide_ir_msg) ioc_info(ioc, "IR shutdown (sending)\n"); init_completion(&ioc->scsih_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { @@ -9670,6 +9671,7 @@ static void scsih_remove(struct pci_dev *pdev) struct _pcie_device *pcie_device, *pcienext; struct workqueue_struct *wq; unsigned long flags; + Mpi2ConfigReply_t mpi_reply; ioc->remove_host = 1; @@ -9684,7 +9686,13 @@ static void scsih_remove(struct pci_dev *pdev) spin_unlock_irqrestore(&ioc->fw_event_lock, flags); if (wq) destroy_workqueue(wq); - + /* + * Copy back the unmodified ioc page1. so that on next driver load, + * current modified changes on ioc page1 won't take effect. + */ + if (ioc->is_aero_ioc) + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, + &ioc->ioc_pg1_copy); /* release all the volumes */ _scsih_ir_shutdown(ioc); sas_remove_host(shost); @@ -9747,6 +9755,7 @@ scsih_shutdown(struct pci_dev *pdev) struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct workqueue_struct *wq; unsigned long flags; + Mpi2ConfigReply_t mpi_reply; ioc->remove_host = 1; @@ -9761,6 +9770,13 @@ scsih_shutdown(struct pci_dev *pdev) spin_unlock_irqrestore(&ioc->fw_event_lock, flags); if (wq) destroy_workqueue(wq); + /* + * Copy back the unmodified ioc page1 so that on next driver load, + * current modified changes on ioc page1 won't take effect. + */ + if (ioc->is_aero_ioc) + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, + &ioc->ioc_pg1_copy); _scsih_ir_shutdown(ioc); mpt3sas_base_detach(ioc); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 60ae2d0feb2b..5324662751bf 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -367,7 +367,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n", (u64)sas_address)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1139,7 +1139,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, (u64)phy->identify.sas_address, phy->number)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1434,7 +1434,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, (u64)phy->identify.sas_address, phy->number, phy_operation)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1911,7 +1911,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, ioc_info(ioc, "%s: sending smp request\n", __func__)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->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/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index 050c8c39d7ed..21d638299ab8 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux. * diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig index 78f7e20a0c1c..79812b80743b 100644 --- a/drivers/scsi/mvsas/Kconfig +++ b/drivers/scsi/mvsas/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver. # @@ -5,25 +6,6 @@ # Copyright 2008 Marvell. <kewei@marvell.com> # Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> # -# This file is licensed under GPLv2. -# -# This file is part of the 88SE64XX/88SE94XX driver. -# -# The 88SE64XX/88SE94XX driver 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; version 2 of the -# License. -# -# The 88SE64XX/88SE94XX driver 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 88SE64XX/88SE94XX Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# config SCSI_MVSAS tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support" diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile index 87b231a5bd5e..75849258e898 100644 --- a/drivers/scsi/mvsas/Makefile +++ b/drivers/scsi/mvsas/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for Marvell 88SE64xx/88SE84xx SAS/SATA driver. # @@ -5,22 +6,6 @@ # Copyright 2008 Marvell. <kewei@marvell.com> # Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> # -# This file is licensed under GPLv2. -# -# 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; version 2 of the -# License. -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA ccflags-$(CONFIG_SCSI_MVSAS_DEBUG) := -DMV_DEBUG diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c index b757d389e32f..1f2b61de8c63 100644 --- a/drivers/scsi/mvsas/mv_64xx.c +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -1,26 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell 88SE64xx hardware specific * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include "mv_sas.h" @@ -678,7 +662,8 @@ static u32 mvs_64xx_spi_read_data(struct mvs_info *mvi) static void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data) { void __iomem *regs = mvi->regs_ex; - iow32(SPI_DATA_REG_64XX, data); + + iow32(SPI_DATA_REG_64XX, data); } diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h index 545889bd9753..c25a5dfe7889 100644 --- a/drivers/scsi/mvsas/mv_64xx.h +++ b/drivers/scsi/mvsas/mv_64xx.h @@ -1,26 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell 88SE64xx hardware specific head file * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #ifndef _MVS64XX_REG_H_ diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index eb5471bc7263..fc0b8eb68204 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -1,26 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell 88SE94xx hardware specific * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include "mv_sas.h" @@ -946,7 +930,8 @@ static u32 mvs_94xx_spi_read_data(struct mvs_info *mvi) static void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data) { void __iomem *regs = mvi->regs_ex - 0x10200; - mw32(SPI_RD_DATA_REG_94XX, data); + + mw32(SPI_RD_DATA_REG_94XX, data); } diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h index 578960803a00..a243182c1345 100644 --- a/drivers/scsi/mvsas/mv_94xx.h +++ b/drivers/scsi/mvsas/mv_94xx.h @@ -1,26 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell 88SE94xx hardware specific head file * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #ifndef _MVS94XX_REG_H_ diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h index 8c4479ab49e8..0e7366fafca9 100644 --- a/drivers/scsi/mvsas/mv_chips.h +++ b/drivers/scsi/mvsas/mv_chips.h @@ -1,26 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell 88SE64xx/88SE94xx register IO interface * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index f5451940d289..199ab49aa047 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -1,26 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell 88SE64xx/88SE94xx const head file * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #ifndef _MV_DEFS_H_ diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 030d911ee374..da719b0694dc 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -1,26 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell 88SE64xx/88SE94xx pci init * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 311d23c727ce..3e0b8ebe257f 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1,26 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell 88SE64xx/88SE94xx main function * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include "mv_sas.h" @@ -1209,7 +1193,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock) mvi_device->dev_type = dev->dev_type; mvi_device->mvi_info = mvi; mvi_device->sas_device = dev; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_id; u8 phy_num = parent_dev->ex_dev.num_phys; struct ex_phy *phy; @@ -1422,7 +1406,7 @@ int mvs_I_T_nexus_reset(struct domain_device *dev) { unsigned long flags; int rc = TMF_RESP_FUNC_FAILED; - struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; if (mvi_dev->dev_status != MVS_DEV_EH) diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 080676c1c9e5..519edc796691 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -1,26 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell 88SE64xx/88SE94xx main function head file * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #ifndef _MV_SAS_H_ @@ -66,9 +50,6 @@ extern struct mvs_info *tgt_mvi; extern const struct mvs_dispatch mvs_64xx_dispatch; extern const struct mvs_dispatch mvs_94xx_dispatch; -#define DEV_IS_EXPANDER(type) \ - ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) - #define bit(n) ((u64)1 << n) #define for_each_phy(__lseq_mask, __mc, __lseq) \ diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 3df02691a092..8906aceda4c4 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -1,24 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell UMI driver * * Copyright 2011 Marvell. <jyli@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include <linux/kernel.h> @@ -211,23 +195,22 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, unsigned int sgnum = scsi_sg_count(scmd); dma_addr_t busaddr; - sg = scsi_sglist(scmd); - *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum, + *sg_count = dma_map_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum, scmd->sc_data_direction); if (*sg_count > mhba->max_sge) { dev_err(&mhba->pdev->dev, "sg count[0x%x] is bigger than max sg[0x%x].\n", *sg_count, mhba->max_sge); - dma_unmap_sg(&mhba->pdev->dev, sg, sgnum, + dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum, scmd->sc_data_direction); return -1; } - for (i = 0; i < *sg_count; i++) { - busaddr = sg_dma_address(&sg[i]); + scsi_for_each_sg(scmd, sg, *sg_count, i) { + busaddr = sg_dma_address(sg); m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); m_sg->flags = 0; - sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i]))); + sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(sg))); if ((i + 1) == *sg_count) m_sg->flags |= 1U << mhba->eot_flag; @@ -752,7 +735,7 @@ static int mvumi_issue_blocked_cmd(struct mvumi_hba *mhba, spin_lock_irqsave(mhba->shost->host_lock, flags); atomic_dec(&cmd->sync_cmd); if (mhba->tag_cmd[cmd->frame->tag]) { - mhba->tag_cmd[cmd->frame->tag] = 0; + mhba->tag_cmd[cmd->frame->tag] = NULL; dev_warn(&mhba->pdev->dev, "TIMEOUT:release tag [%d]\n", cmd->frame->tag); tag_release_one(mhba, &mhba->tag_pool, cmd->frame->tag); @@ -1794,7 +1777,7 @@ static void mvumi_handle_clob(struct mvumi_hba *mhba) cmd = mhba->tag_cmd[ob_frame->tag]; atomic_dec(&mhba->fw_outstanding); - mhba->tag_cmd[ob_frame->tag] = 0; + mhba->tag_cmd[ob_frame->tag] = NULL; tag_release_one(mhba, &mhba->tag_pool, ob_frame->tag); if (cmd->scmd) mvumi_complete_cmd(mhba, cmd, ob_frame); @@ -2139,7 +2122,7 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) spin_lock_irqsave(mhba->shost->host_lock, flags); if (mhba->tag_cmd[cmd->frame->tag]) { - mhba->tag_cmd[cmd->frame->tag] = 0; + mhba->tag_cmd[cmd->frame->tag] = NULL; tag_release_one(mhba, &mhba->tag_pool, cmd->frame->tag); } if (!list_empty(&cmd->queue_pointer)) diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h index 41f168702ac7..ec8cc2207536 100644 --- a/drivers/scsi/mvumi.h +++ b/drivers/scsi/mvumi.h @@ -1,24 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell UMI head file * * Copyright 2011 Marvell. <jyli@marvell.com> - * - * This file is licensed under GPLv2. - * - * 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; version 2 of the - * License. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #ifndef MVUMI_H diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index b8d54ef8cf6d..eb0dd566330a 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -818,7 +818,7 @@ static void myrs_log_event(struct myrs_hba *cs, struct myrs_event *ev) unsigned char ev_type, *ev_msg; struct Scsi_Host *shost = cs->host; struct scsi_device *sdev; - struct scsi_sense_hdr sshdr; + struct scsi_sense_hdr sshdr = {0}; unsigned char sense_info[4]; unsigned char cmd_specific[4]; diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 1a236a3dfd51..e6a95498ac0d 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /****************************************************************************** ** Device driver for the PCI-SCSI NCR538XX controller family. ** ** Copyright (C) 1994 Wolfgang Stanglmeier ** -** 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 program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index 02901c54b08b..8326f5f01e07 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -1,22 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /****************************************************************************** ** Device driver for the PCI-SCSI NCR538XX controller family. ** ** Copyright (C) 1994 Wolfgang Stanglmeier ** Copyright (C) 1998-2001 Gerard Roudier <groudier@free.fr> ** -** 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 program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- ** diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index da4d6e1106c4..70db79254155 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver * Copyright (C) 2001, 2002, 2003 * YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> * GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.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. - * - * * Revision History: * 1.0: Initial Release. * 1.1: Add /proc SDTR status. diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h index c0221829069c..ab0726c070f7 100644 --- a/drivers/scsi/nsp32.h +++ b/drivers/scsi/nsp32.h @@ -1,16 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver * Basic data header - * - * 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 _NSP32_H diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c deleted file mode 100644 index be3c73ebbfde..000000000000 --- a/drivers/scsi/osst.c +++ /dev/null @@ -1,6101 +0,0 @@ -/* - SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying - file Documentation/scsi/st.txt for more information. - - History: - - OnStream SCSI Tape support (osst) cloned from st.c by - Willem Riede (osst@riede.org) Feb 2000 - Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000 - - Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. - Contribution and ideas from several people including (in alphabetical - order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, - Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. - - Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede - email osst@riede.org - - $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $ - - Microscopic alterations - Rik Ling, 2000/12/21 - Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara - Some small formal changes - aeb, 950809 -*/ - -static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $"; -static const char * osst_version = "0.99.4"; - -/* The "failure to reconnect" firmware bug */ -#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ -#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/ -#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7) - -#include <linux/module.h> - -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/sched/signal.h> -#include <linux/proc_fs.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/mtio.h> -#include <linux/ioctl.h> -#include <linux/fcntl.h> -#include <linux/spinlock.h> -#include <linux/vmalloc.h> -#include <linux/blkdev.h> -#include <linux/moduleparam.h> -#include <linux/delay.h> -#include <linux/jiffies.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <asm/dma.h> - -/* The driver prints some debugging information on the console if DEBUG - is defined and non-zero. */ -#define DEBUG 0 - -/* The message level for the debug messages is currently set to KERN_NOTICE - so that people can easily see the messages. Later when the debugging messages - in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ -#define OSST_DEB_MSG KERN_NOTICE - -#include <scsi/scsi.h> -#include <scsi/scsi_dbg.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_driver.h> -#include <scsi/scsi_eh.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_ioctl.h> - -#define ST_KILOBYTE 1024 - -#include "st.h" -#include "osst.h" -#include "osst_options.h" -#include "osst_detect.h" - -static DEFINE_MUTEX(osst_int_mutex); -static int max_dev = 0; -static int write_threshold_kbs = 0; -static int max_sg_segs = 0; - -#ifdef MODULE -MODULE_AUTHOR("Willem Riede"); -MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); - -module_param(max_dev, int, 0444); -MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); - -module_param(write_threshold_kbs, int, 0644); -MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)"); - -module_param(max_sg_segs, int, 0644); -MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)"); -#else -static struct osst_dev_parm { - char *name; - int *val; -} parms[] __initdata = { - { "max_dev", &max_dev }, - { "write_threshold_kbs", &write_threshold_kbs }, - { "max_sg_segs", &max_sg_segs } -}; -#endif - -/* Some default definitions have been moved to osst_options.h */ -#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE) -#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) - -/* The buffer size should fit into the 24 bits for length in the - 6-byte SCSI read and write commands. */ -#if OSST_BUFFER_SIZE >= (2 << 24 - 1) -#error "Buffer size should not exceed (2 << 24 - 1) bytes!" -#endif - -#if DEBUG -static int debugging = 1; -/* uncomment define below to test error recovery */ -// #define OSST_INJECT_ERRORS 1 -#endif - -/* Do not retry! The drive firmware already retries when appropriate, - and when it tries to tell us something, we had better listen... */ -#define MAX_RETRIES 0 - -#define NO_TAPE NOT_READY - -#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1) -#define OSST_WAIT_WRITE_COMPLETE (HZ / 12) -#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2) - -#define OSST_TIMEOUT (200 * HZ) -#define OSST_LONG_TIMEOUT (1800 * HZ) - -#define TAPE_NR(x) (iminor(x) & ((1 << ST_MODE_SHIFT)-1)) -#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) -#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0) -#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1)) - -/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower - 24 bits) */ -#define SET_DENS_AND_BLK 0x10001 - -static int osst_buffer_size = OSST_BUFFER_SIZE; -static int osst_write_threshold = OSST_WRITE_THRESHOLD; -static int osst_max_sg_segs = OSST_MAX_SG; -static int osst_max_dev = OSST_MAX_TAPES; -static int osst_nr_dev; - -static struct osst_tape **os_scsi_tapes = NULL; -static DEFINE_RWLOCK(os_scsi_tapes_lock); - -static int modes_defined = 0; - -static struct osst_buffer *new_tape_buffer(int, int, int); -static int enlarge_buffer(struct osst_buffer *, int); -static void normalize_buffer(struct osst_buffer *); -static int append_to_buffer(const char __user *, struct osst_buffer *, int); -static int from_buffer(struct osst_buffer *, char __user *, int); -static int osst_zero_buffer_tail(struct osst_buffer *); -static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *); -static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *); - -static int osst_probe(struct device *); -static int osst_remove(struct device *); - -static struct scsi_driver osst_template = { - .gendrv = { - .name = "osst", - .owner = THIS_MODULE, - .probe = osst_probe, - .remove = osst_remove, - } -}; - -static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt, - unsigned int cmd_in, unsigned long arg); - -static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip); - -static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt); - -static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt); - -static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending); - -static inline char *tape_name(struct osst_tape *tape) -{ - return tape->drive->disk_name; -} - -/* Routines that handle the interaction with mid-layer SCSI routines */ - - -/* Normalize Sense */ -static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s) -{ - const u8 *ucp; - const u8 *sense = SRpnt->sense; - - s->have_sense = scsi_normalize_sense(SRpnt->sense, - SCSI_SENSE_BUFFERSIZE, &s->sense_hdr); - s->flags = 0; - - if (s->have_sense) { - s->deferred = 0; - s->remainder_valid = - scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64); - switch (sense[0] & 0x7f) { - case 0x71: - s->deferred = 1; - case 0x70: - s->fixed_format = 1; - s->flags = sense[2] & 0xe0; - break; - case 0x73: - s->deferred = 1; - case 0x72: - s->fixed_format = 0; - ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); - s->flags = ucp ? (ucp[3] & 0xe0) : 0; - break; - } - } -} - -/* Convert the result to success code */ -static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) -{ - char *name = tape_name(STp); - int result = SRpnt->result; - u8 * sense = SRpnt->sense, scode; -#if DEBUG - const char *stp; -#endif - struct st_cmdstatus *cmdstatp; - - if (!result) - return 0; - - cmdstatp = &STp->buffer->cmdstat; - osst_analyze_sense(SRpnt, cmdstatp); - - if (cmdstatp->have_sense) - scode = STp->buffer->cmdstat.sense_hdr.sense_key; - else - scode = 0; -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n", - name, result, - SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], - SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); - if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n", - name, scode, sense[12], sense[13]); - if (cmdstatp->have_sense) - __scsi_print_sense(STp->device, name, - SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - else -#endif - if (cmdstatp->have_sense && ( - scode != NO_SENSE && - scode != RECOVERED_ERROR && -/* scode != UNIT_ATTENTION && */ - scode != BLANK_CHECK && - scode != VOLUME_OVERFLOW && - SRpnt->cmd[0] != MODE_SENSE && - SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ - if (cmdstatp->have_sense) { - printk(KERN_WARNING "%s:W: Command with sense data:\n", name); - __scsi_print_sense(STp->device, name, - SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - else { - static int notyetprinted = 1; - - printk(KERN_WARNING - "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", - name, result, driver_byte(result), - host_byte(result)); - if (notyetprinted) { - notyetprinted = 0; - printk(KERN_INFO - "%s:I: This warning may be caused by your scsi controller,\n", name); - printk(KERN_INFO - "%s:I: it has been reported with some Buslogic cards.\n", name); - } - } - } - STp->pos_unknown |= STp->device->was_reset; - - if (cmdstatp->have_sense && scode == RECOVERED_ERROR) { - STp->recover_count++; - STp->recover_erreg++; -#if DEBUG - if (debugging) { - if (SRpnt->cmd[0] == READ_6) - stp = "read"; - else if (SRpnt->cmd[0] == WRITE_6) - stp = "write"; - else - stp = "ioctl"; - printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp, - STp->recover_count); - } -#endif - if ((sense[2] & 0xe0) == 0) - return 0; - } - return (-EIO); -} - - -/* Wakeup from interrupt */ -static void osst_end_async(struct request *req, blk_status_t status) -{ - struct scsi_request *rq = scsi_req(req); - struct osst_request *SRpnt = req->end_io_data; - struct osst_tape *STp = SRpnt->stp; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - - STp->buffer->cmdstat.midlevel_result = SRpnt->result = rq->result; -#if DEBUG - STp->write_pending = 0; -#endif - if (rq->sense_len) - memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE); - if (SRpnt->waiting) - complete(SRpnt->waiting); - - if (SRpnt->bio) { - kfree(mdata->pages); - blk_rq_unmap_user(SRpnt->bio); - } - - blk_put_request(req); -} - -/* osst_request memory management */ -static struct osst_request *osst_allocate_request(void) -{ - return kzalloc(sizeof(struct osst_request), GFP_KERNEL); -} - -static void osst_release_request(struct osst_request *streq) -{ - kfree(streq); -} - -static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries) -{ - struct request *req; - struct scsi_request *rq; - struct page **pages = NULL; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - - int err = 0; - int write = (data_direction == DMA_TO_DEVICE); - - req = blk_get_request(SRpnt->stp->device->request_queue, - write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); - if (IS_ERR(req)) - return DRIVER_ERROR << 24; - - rq = scsi_req(req); - req->rq_flags |= RQF_QUIET; - - SRpnt->bio = NULL; - - if (use_sg) { - struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; - int i; - - pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL); - if (!pages) - goto free_req; - - for_each_sg(sgl, sg, use_sg, i) - pages[i] = sg_page(sg); - - mdata->null_mapped = 1; - - mdata->page_order = get_order(sgl[0].length); - mdata->nr_entries = - DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); - mdata->offset = 0; - - err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); - if (err) { - kfree(pages); - goto free_req; - } - SRpnt->bio = req->bio; - mdata->pages = pages; - - } else if (bufflen) { - err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); - if (err) - goto free_req; - } - - rq->cmd_len = cmd_len; - memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(rq->cmd, cmd, rq->cmd_len); - req->timeout = timeout; - rq->retries = retries; - req->end_io_data = SRpnt; - - blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async); - return 0; -free_req: - blk_put_request(req); - return DRIVER_ERROR << 24; -} - -/* Do the scsi command. Waits until command performed if do_wait is true. - Otherwise osst_write_behind_check() is used to check that the command - has finished. */ -static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp, - unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait) -{ - unsigned char *bp; - unsigned short use_sg; -#ifdef OSST_INJECT_ERRORS - static int inject = 0; - static int repeat = 0; -#endif - struct completion *waiting; - - /* if async, make sure there's no command outstanding */ - if (!do_wait && ((STp->buffer)->last_SRpnt)) { - printk(KERN_ERR "%s: Async command already active.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - - if (SRpnt == NULL) { - SRpnt = osst_allocate_request(); - if (SRpnt == NULL) { - printk(KERN_ERR "%s: Can't allocate SCSI request.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - SRpnt->stp = STp; - } - - /* If async IO, set last_SRpnt. This ptr tells write_behind_check - which IO is outstanding. It's nulled out when the IO completes. */ - if (!do_wait) - (STp->buffer)->last_SRpnt = SRpnt; - - waiting = &STp->wait; - init_completion(waiting); - SRpnt->waiting = waiting; - - use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0; - if (use_sg) { - bp = (char *)&(STp->buffer->sg[0]); - if (STp->buffer->sg_segs < use_sg) - use_sg = STp->buffer->sg_segs; - } - else - bp = (STp->buffer)->b_data; - - memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); - STp->buffer->cmdstat.have_sense = 0; - STp->buffer->syscall_result = 0; - - if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, - use_sg, timeout, retries)) - /* could not allocate the buffer or request was too large */ - (STp->buffer)->syscall_result = (-EBUSY); - else if (do_wait) { - wait_for_completion(waiting); - SRpnt->waiting = NULL; - STp->buffer->syscall_result = osst_chk_result(STp, SRpnt); -#ifdef OSST_INJECT_ERRORS - if (STp->buffer->syscall_result == 0 && - cmd[0] == READ_6 && - cmd[4] && - ( (++ inject % 83) == 29 || - (STp->first_frame_position == 240 - /* or STp->read_error_frame to fail again on the block calculated above */ && - ++repeat < 3))) { - printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp)); - STp->buffer->last_result_fatal = 1; - } -#endif - } - return SRpnt; -} - - -/* Handle the write-behind checking (downs the semaphore) */ -static void osst_write_behind_check(struct osst_tape *STp) -{ - struct osst_buffer * STbuffer; - - STbuffer = STp->buffer; - -#if DEBUG - if (STp->write_pending) - STp->nbr_waits++; - else - STp->nbr_finished++; -#endif - wait_for_completion(&(STp->wait)); - STp->buffer->last_SRpnt->waiting = NULL; - - STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt); - - if (STp->buffer->syscall_result) - STp->buffer->syscall_result = - osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1); - else - STp->first_frame_position++; - - osst_release_request(STp->buffer->last_SRpnt); - - if (STbuffer->writing < STbuffer->buffer_bytes) - printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n"); - - STbuffer->last_SRpnt = NULL; - STbuffer->buffer_bytes -= STbuffer->writing; - STbuffer->writing = 0; - - return; -} - - - -/* Onstream specific Routines */ -/* - * Initialize the OnStream AUX - */ -static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number, - int logical_blk_num, int blk_sz, int blk_cnt) -{ - os_aux_t *aux = STp->buffer->aux; - os_partition_t *par = &aux->partition; - os_dat_t *dat = &aux->dat; - - if (STp->raw) return; - - memset(aux, 0, sizeof(*aux)); - aux->format_id = htonl(0); - memcpy(aux->application_sig, "LIN4", 4); - aux->hdwr = htonl(0); - aux->frame_type = frame_type; - - switch (frame_type) { - case OS_FRAME_TYPE_HEADER: - aux->update_frame_cntr = htonl(STp->update_frame_cntr); - par->partition_num = OS_CONFIG_PARTITION; - par->par_desc_ver = OS_PARTITION_VERSION; - par->wrt_pass_cntr = htons(0xffff); - /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */ - par->first_frame_ppos = htonl(0); - par->last_frame_ppos = htonl(0xbb7); - aux->frame_seq_num = htonl(0); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(0); - aux->next_mark_ppos = htonl(STp->first_mark_ppos); - break; - case OS_FRAME_TYPE_DATA: - case OS_FRAME_TYPE_MARKER: - dat->dat_sz = 8; - dat->reserved1 = 0; - dat->entry_cnt = 1; - dat->reserved3 = 0; - dat->dat_list[0].blk_sz = htonl(blk_sz); - dat->dat_list[0].blk_cnt = htons(blk_cnt); - dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER? - OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA; - dat->dat_list[0].reserved = 0; - case OS_FRAME_TYPE_EOD: - aux->update_frame_cntr = htonl(0); - par->partition_num = OS_DATA_PARTITION; - par->par_desc_ver = OS_PARTITION_VERSION; - par->wrt_pass_cntr = htons(STp->wrt_pass_cntr); - par->first_frame_ppos = htonl(STp->first_data_ppos); - par->last_frame_ppos = htonl(STp->capacity); - aux->frame_seq_num = htonl(frame_seq_number); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(logical_blk_num); - break; - default: ; /* probably FILL */ - } - aux->filemark_cnt = htonl(STp->filemark_cnt); - aux->phys_fm = htonl(0xffffffff); - aux->last_mark_ppos = htonl(STp->last_mark_ppos); - aux->last_mark_lbn = htonl(STp->last_mark_lbn); -} - -/* - * Verify that we have the correct tape frame - */ -static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet) -{ - char * name = tape_name(STp); - os_aux_t * aux = STp->buffer->aux; - os_partition_t * par = &(aux->partition); - struct st_partstat * STps = &(STp->ps[STp->partition]); - unsigned int blk_cnt, blk_sz, i; - - if (STp->raw) { - if (STp->buffer->syscall_result) { - for (i=0; i < STp->buffer->sg_segs; i++) - memset(page_address(sg_page(&STp->buffer->sg[i])), - 0, STp->buffer->sg[i].length); - strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); - } else - STp->buffer->buffer_bytes = OS_FRAME_SIZE; - return 1; - } - if (STp->buffer->syscall_result) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name); -#endif - return 0; - } - if (ntohl(aux->format_id) != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id)); -#endif - goto err_out; - } - if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 && - (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name); -#endif - goto err_out; - } - if (par->partition_num != OS_DATA_PARTITION) { - if (!STp->linux_media || STp->linux_media_version != 2) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n", - name, par->partition_num); -#endif - goto err_out; - } - } - if (par->par_desc_ver != OS_PARTITION_VERSION) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver); -#endif - goto err_out; - } - if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", - name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); -#endif - goto err_out; - } - if (aux->frame_type != OS_FRAME_TYPE_DATA && - aux->frame_type != OS_FRAME_TYPE_EOD && - aux->frame_type != OS_FRAME_TYPE_MARKER) { - if (!quiet) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); -#endif - } - goto err_out; - } - if (aux->frame_type == OS_FRAME_TYPE_EOD && - STp->first_frame_position < STp->eod_frame_ppos) { - printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name, - STp->first_frame_position); - goto err_out; - } - if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { - if (!quiet) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", - name, ntohl(aux->frame_seq_num), frame_seq_number); -#endif - } - goto err_out; - } - if (aux->frame_type == OS_FRAME_TYPE_MARKER) { - STps->eof = ST_FM_HIT; - - i = ntohl(aux->filemark_cnt); - if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt || - STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name, - STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected", - i, STp->first_frame_position - 1); -#endif - STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1); - if (i >= STp->filemark_cnt) - STp->filemark_cnt = i+1; - } - } - if (aux->frame_type == OS_FRAME_TYPE_EOD) { - STps->eof = ST_EOD_1; - STp->frame_in_buffer = 1; - } - if (aux->frame_type == OS_FRAME_TYPE_DATA) { - blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt); - blk_sz = ntohl(aux->dat.dat_list[0].blk_sz); - STp->buffer->buffer_bytes = blk_cnt * blk_sz; - STp->buffer->read_pointer = 0; - STp->frame_in_buffer = 1; - - /* See what block size was used to write file */ - if (STp->block_size != blk_sz && blk_sz > 0) { - printk(KERN_INFO - "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n", - name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k', - STp->block_size<1024?STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); - STp->block_size = blk_sz; - STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz; - } - STps->eof = ST_NOEOF; - } - STp->frame_seq_number = ntohl(aux->frame_seq_num); - STp->logical_blk_num = ntohl(aux->logical_blk_num); - return 1; - -err_out: - if (STp->read_error_frame == 0) - STp->read_error_frame = STp->first_frame_position - 1; - return 0; -} - -/* - * Wait for the unit to become Ready - */ -static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned timeout, int initial_delay) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name); -#endif - - if (initial_delay > 0) - msleep(jiffies_to_msecs(initial_delay)); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - - while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && - (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) || - ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 && - SRpnt->sense[13] == 0 ) )) { -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - msleep(100); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - } - *aSRpnt = SRpnt; -#if DEBUG - debugging = dbg; -#endif - if ( STp->buffer->syscall_result && - osst_write_error_recovery(STp, aSRpnt, 0) ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, - STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - return (-EIO); - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name); -#endif - return 0; -} - -/* - * Wait for a tape to be inserted in the unit - */ -static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name); -#endif - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - - while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) { -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - msleep(100); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - } - *aSRpnt = SRpnt; -#if DEBUG - debugging = dbg; -#endif - if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 && - SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name); - printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, - STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - return 0; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name); -#endif - return 1; -} - -static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame) -{ - int retval; - - osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */ - retval = osst_set_frame_position(STp, aSRpnt, frame, 0); - if (retval) return (retval); - osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE); - return (osst_get_frame_position(STp, aSRpnt)); -} - -/* - * Wait for write(s) to complete - */ -static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int result = 0; - int delay = OSST_WAIT_WRITE_COMPLETE; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name); -#endif - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - if (STp->buffer->syscall_result) { - if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) { - if (SRpnt->sense[13] == 8) { - delay = OSST_WAIT_LONG_WRITE_COMPLETE; - } - } else - result = osst_write_error_recovery(STp, aSRpnt, 0); - } - result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay); - STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; - - return (result); -} - -#define OSST_POLL_PER_SEC 10 -static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to) -{ - unsigned long startwait = jiffies; - char * name = tape_name(STp); -#if DEBUG - char notyetprinted = 1; -#endif - if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) - printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name); - - while (time_before (jiffies, startwait + to*HZ)) - { - int result; - result = osst_get_frame_position(STp, aSRpnt); - if (result == -EIO) - if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0) - return 0; /* successful recovery leaves drive ready for frame */ - if (result < 0) break; - if (STp->first_frame_position == curr && - ((minlast < 0 && - (signed)STp->last_frame_position > (signed)curr + minlast) || - (minlast >= 0 && STp->cur_frames > minlast) - ) && result >= 0) - { -#if DEBUG - if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC)) - printk (OSST_DEB_MSG - "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, - result, (jiffies-startwait)/HZ, - (((jiffies-startwait)%HZ)*10)/HZ); -#endif - return 0; - } -#if DEBUG - if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted) - { - printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, result); - notyetprinted--; - } -#endif - msleep(1000 / OSST_POLL_PER_SEC); - } -#if DEBUG - printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, - (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); -#endif - return -EBUSY; -} - -static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing) -{ - struct osst_request * SRpnt; - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned long startwait = jiffies; - int retval = 1; - char * name = tape_name(STp); - - if (writing) { - char mybuf[24]; - char * olddata = STp->buffer->b_data; - int oldsize = STp->buffer->buffer_size; - - /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */ - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, - MAX_RETRIES, 1); - - while (retval && time_before (jiffies, startwait + 5*60*HZ)) { - - if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) { - - /* some failure - not just not-ready */ - retval = osst_write_error_recovery(STp, aSRpnt, 0); - break; - } - schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC); - - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_POSITION; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout, - MAX_RETRIES, 1); - - retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 ); - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - } - if (retval) - printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name); - } else - /* TODO - figure out which error conditions can be handled */ - if (STp->buffer->syscall_result) - printk(KERN_WARNING - "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name, - (*aSRpnt)->sense[ 2] & 0x0f, - (*aSRpnt)->sense[12], - (*aSRpnt)->sense[13]); - - return retval; -} - -/* - * Read the next OnStream tape frame at the current location - */ -static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int retval = 0; -#if DEBUG - os_aux_t * aux = STp->buffer->aux; - char * name = tape_name(STp); -#endif - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout)) - retval = osst_recover_wait_frame(STp, aSRpnt, 0); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = 1; - cmd[4] = 1; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return (-EBUSY); - - if ((STp->buffer)->syscall_result) { - retval = 1; - if (STp->read_error_frame == 0) { - STp->read_error_frame = STp->first_frame_position; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame); -#endif - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - name, - SRpnt->sense[0], SRpnt->sense[1], - SRpnt->sense[2], SRpnt->sense[3], - SRpnt->sense[4], SRpnt->sense[5], - SRpnt->sense[6], SRpnt->sense[7]); -#endif - } - else - STp->first_frame_position++; -#if DEBUG - if (debugging) { - char sig[8]; int i; - for (i=0;i<4;i++) - sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i]; - sig[4] = '\0'; - printk(OSST_DEB_MSG - "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig, - ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr), - aux->frame_type==1?"EOD":aux->frame_type==2?"MARK": - aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", - ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), - ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) ); - if (aux->frame_type==2) - printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name, - ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn)); - printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval); - } -#endif - return (retval); -} - -static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - struct osst_request * SRpnt ; - unsigned char cmd[MAX_COMMAND_SIZE]; - int retval = 0; - char * name = tape_name(STp); - - if (STps->rw != ST_READING) { /* Initialize read operation */ - if (STps->rw == ST_WRITING || STp->dirty) { - STp->write_type = OS_WRITE_DATA; - osst_flush_write_buffer(STp, aSRpnt); - osst_flush_drive_buffer(STp, aSRpnt); - } - STps->rw = ST_READING; - STp->frame_in_buffer = 0; - - /* - * Issue a read 0 command to get the OnStream drive - * read frames into its buffer. - */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = 1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if ((retval = STp->buffer->syscall_result)) - printk(KERN_WARNING "%s:W: Error starting read ahead\n", name); - } - - return retval; -} - -static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, - int frame_seq_number, int quiet) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - char * name = tape_name(STp); - int cnt = 0, - bad = 0, - past = 0, - x, - position; - - /* - * If we want just any frame (-1) and there is a frame in the buffer, return it - */ - if (frame_seq_number == -1 && STp->frame_in_buffer) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number); -#endif - return (STps->eof); - } - /* - * Search and wait for the next logical tape frame - */ - while (1) { - if (cnt++ > 400) { - printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n", - name, frame_seq_number); - if (STp->read_error_frame) { - osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n", - name, STp->read_error_frame); -#endif - STp->read_error_frame = 0; - STp->abort_count++; - } - return (-EIO); - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n", - name, frame_seq_number, cnt); -#endif - if ( osst_initiate_read(STp, aSRpnt) - || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { - if (STp->raw) - return (-EIO); - position = osst_get_frame_position(STp, aSRpnt); - if (position >= 0xbae && position < 0xbb8) - position = 0xbb8; - else if (position > STp->eod_frame_ppos || ++bad == 10) { - position = STp->read_error_frame - 1; - bad = 0; - } - else { - position += 29; - cnt += 19; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n", - name, position); -#endif - osst_set_frame_position(STp, aSRpnt, position, 0); - continue; - } - if (osst_verify_frame(STp, frame_seq_number, quiet)) - break; - if (osst_verify_frame(STp, -1, quiet)) { - x = ntohl(STp->buffer->aux->frame_seq_num); - if (STp->fast_open) { - printk(KERN_WARNING - "%s:W: Found logical frame %d instead of %d after fast open\n", - name, x, frame_seq_number); - STp->header_ok = 0; - STp->read_error_frame = 0; - return (-EIO); - } - if (x > frame_seq_number) { - if (++past > 3) { - /* positioning backwards did not bring us to the desired frame */ - position = STp->read_error_frame - 1; - } - else { - position = osst_get_frame_position(STp, aSRpnt) - + frame_seq_number - x - 1; - - if (STp->first_frame_position >= 3000 && position < 3000) - position -= 10; - } -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Found logical frame %d while looking for %d: back up %d\n", - name, x, frame_seq_number, - STp->first_frame_position - position); -#endif - osst_set_frame_position(STp, aSRpnt, position, 0); - cnt += 10; - } - else - past = 0; - } - if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name); -#endif - osst_set_frame_position(STp, aSRpnt, 0xbb8, 0); - cnt--; - } - STp->frame_in_buffer = 0; - } - if (cnt > 1) { - STp->recover_count++; - STp->recover_erreg++; - printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", - name, STp->read_error_frame); - } - STp->read_count++; - -#if DEBUG - if (debugging || STps->eof) - printk(OSST_DEB_MSG - "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n", - name, frame_seq_number, STp->frame_seq_number, STps->eof); -#endif - STp->fast_open = 0; - STp->read_error_frame = 0; - return (STps->eof); -} - -static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - char * name = tape_name(STp); - int retries = 0; - int frame_seq_estimate, ppos_estimate, move; - - if (logical_blk_num < 0) logical_blk_num = 0; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n", - name, logical_blk_num, STp->logical_blk_num, - STp->block_size<1024?STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); -#endif - /* Do we know where we are? */ - if (STps->drv_block >= 0) { - move = logical_blk_num - STp->logical_blk_num; - if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; - move /= (OS_DATA_SIZE / STp->block_size); - frame_seq_estimate = STp->frame_seq_number + move; - } else - frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE; - - if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10; - else ppos_estimate = frame_seq_estimate + 20; - while (++retries < 10) { - if (ppos_estimate > STp->eod_frame_ppos-2) { - frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate; - ppos_estimate = STp->eod_frame_ppos - 2; - } - if (frame_seq_estimate < 0) { - frame_seq_estimate = 0; - ppos_estimate = 10; - } - osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0); - if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) { - /* we've located the estimated frame, now does it have our block? */ - if (logical_blk_num < STp->logical_blk_num || - logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) { - if (STps->eof == ST_FM_HIT) - move = logical_blk_num < STp->logical_blk_num? -2 : 1; - else { - move = logical_blk_num - STp->logical_blk_num; - if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; - move /= (OS_DATA_SIZE / STp->block_size); - } - if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", - name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, - STp->logical_blk_num, logical_blk_num, move); -#endif - frame_seq_estimate += move; - ppos_estimate += move; - continue; - } else { - STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size; - STp->buffer->buffer_bytes -= STp->buffer->read_pointer; - STp->logical_blk_num = logical_blk_num; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n", - name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, - STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, - STp->block_size); -#endif - STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); - if (STps->eof == ST_FM_HIT) { - STps->drv_file++; - STps->drv_block = 0; - } else { - STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? - STp->logical_blk_num - - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): - -1; - } - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; - return 0; - } - } - if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0) - goto error; - /* we are not yet at the estimated frame, adjust our estimate of its physical position */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", - name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, - STp->logical_blk_num, logical_blk_num); -#endif - if (frame_seq_estimate != STp->frame_seq_number) - ppos_estimate += frame_seq_estimate - STp->frame_seq_number; - else - break; - } -error: - printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", - name, logical_blk_num, STp->logical_blk_num, retries); - return (-EIO); -} - -/* The values below are based on the OnStream frame payload size of 32K == 2**15, - * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block - * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions - * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. - */ -#define OSST_FRAME_SHIFT 6 -#define OSST_SECTOR_SHIFT 9 -#define OSST_SECTOR_MASK 0x03F - -static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int sector; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG - "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n", - name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, - STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, - STp->ps[STp->partition].rw == ST_WRITING?'w':'r', - STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes: - STp->buffer->read_pointer, STp->ps[STp->partition].eof); -#endif - /* do we know where we are inside a file? */ - if (STp->ps[STp->partition].drv_block >= 0) { - sector = (STp->frame_in_buffer ? STp->first_frame_position-1 : - STp->first_frame_position) << OSST_FRAME_SHIFT; - if (STp->ps[STp->partition].rw == ST_WRITING) - sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; - else - sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; - } else { - sector = osst_get_frame_position(STp, aSRpnt); - if (sector > 0) - sector <<= OSST_FRAME_SHIFT; - } - return sector; -} - -static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - int frame = sector >> OSST_FRAME_SHIFT, - offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, - r; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n", - name, sector, frame, offset); -#endif - if (frame < 0 || frame >= STp->capacity) return (-ENXIO); - - if (frame <= STp->first_data_ppos) { - STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0; - return (osst_set_frame_position(STp, aSRpnt, frame, 0)); - } - r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0); - if (r < 0) return r; - - r = osst_get_logical_frame(STp, aSRpnt, -1, 1); - if (r < 0) return r; - - if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO); - - if (offset) { - STp->logical_blk_num += offset / STp->block_size; - STp->buffer->read_pointer = offset; - STp->buffer->buffer_bytes -= offset; - } else { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; - } - STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); - if (STps->eof == ST_FM_HIT) { - STps->drv_file++; - STps->drv_block = 0; - } else { - STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? - STp->logical_blk_num - - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): - -1; - } - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", - name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, - STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof); -#endif - return 0; -} - -/* - * Read back the drive's internal buffer contents, as a part - * of the write error recovery mechanism for old OnStream - * firmware revisions. - * Precondition for this function to work: all frames in the - * drive's buffer must be of one type (DATA, MARK or EOD)! - */ -static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int frame, unsigned int skip, int pending) -{ - struct osst_request * SRpnt = * aSRpnt; - unsigned char * buffer, * p; - unsigned char cmd[MAX_COMMAND_SIZE]; - int flag, new_frame, i; - int nframes = STp->cur_frames; - int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num) - - (nframes + pending - 1); - int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num) - - (nframes + pending - 1) * blks_per_frame; - char * name = tape_name(STp); - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; -#endif - - if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL) - return (-EIO); - - printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", - name, nframes, pending?" and one that was pending":""); - - osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE])); -#if DEBUG - if (pending && debugging) - printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", - name, frame_seq_number + nframes, - logical_blk_num + nframes * blks_per_frame, - p[0], p[1], p[2], p[3]); -#endif - for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = 0x3C; /* Buffer Read */ - cmd[1] = 6; /* Retrieve Faulty Block */ - cmd[7] = 32768 >> 8; - cmd[8] = 32768 & 0xff; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - - if ((STp->buffer)->syscall_result || !SRpnt) { - printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); - vfree(buffer); - *aSRpnt = SRpnt; - return (-EIO); - } - osst_copy_from_buffer(STp->buffer, p); -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n", - name, frame_seq_number + i, p[0], p[1], p[2], p[3]); -#endif - } - *aSRpnt = SRpnt; - osst_get_frame_position(STp, aSRpnt); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames); -#endif - /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ - /* In the header we don't actually re-write the frames that fail, just the ones after them */ - - for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) { - - if (flag) { - if (STp->write_type == OS_WRITE_HEADER) { - i += skip; - p += skip * OS_DATA_SIZE; - } - else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990) - new_frame = 3000-i; - else - new_frame += skip; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n", - name, new_frame+i, frame_seq_number+i); -#endif - osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); - osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE); - osst_get_frame_position(STp, aSRpnt); - SRpnt = * aSRpnt; - - if (new_frame > frame + 1000) { - printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name); - vfree(buffer); - return (-EIO); - } - if ( i >= nframes + pending ) break; - flag = 0; - } - osst_copy_to_buffer(STp->buffer, p); - /* - * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type! - */ - osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i, - logical_blk_num + i*blks_per_frame, - ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame); - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG - "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", - name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, - p[0], p[1], p[2], p[3]); -#endif - SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - - if (STp->buffer->syscall_result) - flag = 1; - else { - p += OS_DATA_SIZE; i++; - - /* if we just sent the last frame, wait till all successfully written */ - if ( i == nframes + pending ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name); -#endif - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - flag = STp->buffer->syscall_result; - while ( !flag && time_before(jiffies, startwait + 60*HZ) ) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, - MAX_RETRIES, 1); - - if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && - (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) { - /* in the process of becoming ready */ - msleep(100); - continue; - } - if (STp->buffer->syscall_result) - flag = 1; - break; - } -#if DEBUG - debugging = dbg; - printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); -#endif - } - } - *aSRpnt = SRpnt; - if (flag) { - if ((SRpnt->sense[ 2] & 0x0f) == 13 && - SRpnt->sense[12] == 0 && - SRpnt->sense[13] == 2) { - printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name); - vfree(buffer); - return (-EIO); /* hit end of tape = fail */ - } - i = ((SRpnt->sense[3] << 24) | - (SRpnt->sense[4] << 16) | - (SRpnt->sense[5] << 8) | - SRpnt->sense[6] ) - new_frame; - p = &buffer[i * OS_DATA_SIZE]; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i); -#endif - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n", - name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames); -#endif - } - } - if (flag) { - /* error recovery did not successfully complete */ - printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name, - STp->write_type == OS_WRITE_HEADER?"header":"body"); - } - if (!pending) - osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */ - vfree(buffer); - return 0; -} - -static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int frame, unsigned int skip, int pending) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - char * name = tape_name(STp); - int expected = 0; - int attempts = 1000 / skip; - int flag = 1; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; -#endif - - while (attempts && time_before(jiffies, startwait + 60*HZ)) { - if (flag) { -#if DEBUG - debugging = dbg; -#endif - if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990) - frame = 3000-skip; - expected = frame+skip+STp->cur_frames+pending; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n", - name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending); -#endif - osst_set_frame_position(STp, aSRpnt, frame + skip, 1); - flag = 0; - attempts--; - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n", - name, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames); -#endif - frame = STp->last_frame_position; - flag = 1; - continue; - } - if (pending && STp->cur_frames < 50) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n", - name, STp->frame_seq_number-1, STp->first_frame_position); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - - if (STp->buffer->syscall_result) { /* additional write error */ - if ((SRpnt->sense[ 2] & 0x0f) == 13 && - SRpnt->sense[12] == 0 && - SRpnt->sense[13] == 2) { - printk(KERN_ERR - "%s:E: Volume overflow in write error recovery\n", - name); - break; /* hit end of tape = fail */ - } - flag = 1; - } - else - pending = 0; - - continue; - } - if (STp->cur_frames == 0) { -#if DEBUG - debugging = dbg; - printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); -#endif - if (STp->first_frame_position != expected) { - printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", - name, STp->first_frame_position, expected); - return (-EIO); - } - return 0; - } -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name); -#if DEBUG - debugging = dbg; -#endif - return (-EIO); -} - -/* - * Error recovery algorithm for the OnStream tape. - */ - -static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending) -{ - struct osst_request * SRpnt = * aSRpnt; - struct st_partstat * STps = & STp->ps[STp->partition]; - char * name = tape_name(STp); - int retval = 0; - int rw_state; - unsigned int frame, skip; - - rw_state = STps->rw; - - if ((SRpnt->sense[ 2] & 0x0f) != 3 - || SRpnt->sense[12] != 12 - || SRpnt->sense[13] != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name, - SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]); -#endif - return (-EIO); - } - frame = (SRpnt->sense[3] << 24) | - (SRpnt->sense[4] << 16) | - (SRpnt->sense[5] << 8) | - SRpnt->sense[6]; - skip = SRpnt->sense[9]; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip); -#endif - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n", - name, STp->first_frame_position, STp->last_frame_position); -#endif - switch (STp->write_type) { - case OS_WRITE_DATA: - case OS_WRITE_EOD: - case OS_WRITE_NEW_MARK: - printk(KERN_WARNING - "%s:I: Relocating %d buffered logical frames from position %u to %u\n", - name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); - if (STp->os_fw_rev >= 10600) - retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); - else - retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name, - retval?"E" :"I", - retval?"" :"Don't worry, ", - retval?" not ":" "); - break; - case OS_WRITE_LAST_MARK: - printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name); - osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); - retval = -EIO; - break; - case OS_WRITE_HEADER: - printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name); - retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending); - break; - default: - printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name); - osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); - } - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", - name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); - printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num); -#endif - if (retval == 0) { - STp->recover_count++; - STp->recover_erreg++; - } else - STp->abort_count++; - - STps->rw = rw_state; - return retval; -} - -static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - char * name = tape_name(STp); - int cnt; - int last_mark_ppos = -1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name); -#endif - return -EIO; - } - if (STp->linux_media_version >= 4) { - /* - * direct lookup in header filemark list - */ - cnt = ntohl(STp->buffer->aux->filemark_cnt); - if (STp->header_ok && - STp->header_cache != NULL && - (cnt - mt_count) >= 0 && - (cnt - mt_count) < OS_FM_TAB_MAX && - (cnt - mt_count) < STp->filemark_cnt && - STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos) - - last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]); -#if DEBUG - if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, - STp->header_cache == NULL?"lack of header cache":"count out of range"); - else - printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - name, cnt, - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == - STp->buffer->aux->last_mark_ppos))?"match":"error", - mt_count, last_mark_ppos); -#endif - if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { - osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, last_mark_ppos); - return (-EIO); - } - goto found; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name); -#endif - } - cnt = 0; - while (cnt != mt_count) { - last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos); - if (last_mark_ppos == -1) - return (-EIO); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); - cnt++; - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, last_mark_ppos); - return (-EIO); - } - } -found: - if (mt_op == MTBSFM) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * ADRL 1.1 compatible "slow" space filemarks fwd version - * - * Just scans for the filemark sequentially. - */ -static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - int cnt = 0; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); -#endif - return (-EIO); - } - while (1) { - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) - cnt++; - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); -#endif - if (STp->first_frame_position > STp->eod_frame_ppos+1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n", - name, STp->eod_frame_ppos, STp->first_frame_position-1); -#endif - STp->eod_frame_ppos = STp->first_frame_position-1; - } - return (-EIO); - } - if (cnt == mt_count) - break; - STp->frame_in_buffer = 0; - } - if (mt_op == MTFSF) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * Fast linux specific version of OnStream FSF - */ -static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - char * name = tape_name(STp); - int cnt = 0, - next_mark_ppos = -1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); -#endif - return (-EIO); - } - - if (STp->linux_media_version >= 4) { - /* - * direct lookup in header filemark list - */ - cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1; - if (STp->header_ok && - STp->header_cache != NULL && - (cnt + mt_count) < OS_FM_TAB_MAX && - (cnt + mt_count) < STp->filemark_cnt && - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos))) - - next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]); -#if DEBUG - if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, - STp->header_cache == NULL?"lack of header cache":"count out of range"); - else - printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - name, cnt, - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == - STp->buffer->aux->last_mark_ppos))?"match":"error", - mt_count, next_mark_ppos); -#endif - if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); - } else { - osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, next_mark_ppos); - return (-EIO); - } - if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) { - printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n", - name, cnt+mt_count, next_mark_ppos, - ntohl(STp->buffer->aux->filemark_cnt)); - return (-EIO); - } - } - } else { - /* - * Find nearest (usually previous) marker, then jump from marker to marker - */ - while (1) { - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) - break; - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); -#endif - return (-EIO); - } - if (ntohl(STp->buffer->aux->filemark_cnt) == 0) { - if (STp->first_mark_ppos == -1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); - } - osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n", - name, STp->first_mark_ppos); - return (-EIO); - } - } else { - if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0) - return (-EIO); - mt_count++; - } - } - cnt++; - while (cnt != mt_count) { - next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos); - if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt); - } -#if DEBUG - else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); - cnt++; - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, next_mark_ppos); - return (-EIO); - } - } - } - if (mt_op == MTFSF) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * In debug mode, we want to see as many errors as possible - * to test the error recovery mechanism. - */ -#if DEBUG -static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = * aSRpnt; - char * name = tape_name(STp); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH; - - (STp->buffer)->b_data[0] = cmd[4] - 1; - (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ - (STp->buffer)->b_data[2] = 0; /* Reserved */ - (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7); - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries; - - if (debugging) - printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries); - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result) - printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries); -} -#endif - - -static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int result; - int this_mark_ppos = STp->first_frame_position; - int this_mark_lbn = STp->logical_blk_num; -#if DEBUG - char * name = tape_name(STp); -#endif - - if (STp->raw) return 0; - - STp->write_type = OS_WRITE_NEW_MARK; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", - name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn); -#endif - STp->dirty = 1; - result = osst_flush_write_buffer(STp, aSRpnt); - result |= osst_flush_drive_buffer(STp, aSRpnt); - STp->last_mark_ppos = this_mark_ppos; - STp->last_mark_lbn = this_mark_lbn; - if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) - STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos); - if (STp->filemark_cnt++ == 0) - STp->first_mark_ppos = this_mark_ppos; - return result; -} - -static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int result; -#if DEBUG - char * name = tape_name(STp); -#endif - - if (STp->raw) return 0; - - STp->write_type = OS_WRITE_EOD; - STp->eod_frame_ppos = STp->first_frame_position; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name, - STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num); -#endif - STp->dirty = 1; - - result = osst_flush_write_buffer(STp, aSRpnt); - result |= osst_flush_drive_buffer(STp, aSRpnt); - STp->eod_frame_lfa = --(STp->frame_seq_number); - return result; -} - -static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) -{ - char * name = tape_name(STp); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where); -#endif - osst_wait_ready(STp, aSRpnt, 60 * 5, 0); - osst_set_frame_position(STp, aSRpnt, where, 0); - STp->write_type = OS_WRITE_FILLER; - while (count--) { - memcpy(STp->buffer->b_data, "Filler", 6); - STp->buffer->buffer_bytes = 6; - STp->dirty = 1; - if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name); - return (-EIO); - } - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name); -#endif - return osst_flush_drive_buffer(STp, aSRpnt); -} - -static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) -{ - char * name = tape_name(STp); - int result; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where); -#endif - osst_wait_ready(STp, aSRpnt, 60 * 5, 0); - osst_set_frame_position(STp, aSRpnt, where, 0); - STp->write_type = OS_WRITE_HEADER; - while (count--) { - osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache); - STp->buffer->buffer_bytes = sizeof(os_header_t); - STp->dirty = 1; - if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "%s:I: Couldn't write header frame\n", name); - return (-EIO); - } - } - result = osst_flush_drive_buffer(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done"); -#endif - return result; -} - -static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod) -{ - os_header_t * header; - int result; - char * name = tape_name(STp); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name); -#endif - if (STp->raw) return 0; - - if (STp->header_cache == NULL) { - if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); - return (-ENOMEM); - } - memset(STp->header_cache, 0, sizeof(os_header_t)); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name); -#endif - } - if (STp->header_ok) STp->update_frame_cntr++; - else STp->update_frame_cntr = 0; - - header = STp->header_cache; - strcpy(header->ident_str, "ADR_SEQ"); - header->major_rev = 1; - header->minor_rev = 4; - header->ext_trk_tb_off = htons(17192); - header->pt_par_num = 1; - header->partition[0].partition_num = OS_DATA_PARTITION; - header->partition[0].par_desc_ver = OS_PARTITION_VERSION; - header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr); - header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos); - header->partition[0].last_frame_ppos = htonl(STp->capacity); - header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos); - header->cfg_col_width = htonl(20); - header->dat_col_width = htonl(1500); - header->qfa_col_width = htonl(0); - header->ext_track_tb.nr_stream_part = 1; - header->ext_track_tb.et_ent_sz = 32; - header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0; - header->ext_track_tb.dat_ext_trk_ey.fmt = 1; - header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736); - header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0; - header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa); - header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos); - header->dat_fm_tab.fm_part_num = 0; - header->dat_fm_tab.fm_tab_ent_sz = 4; - header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX? - STp->filemark_cnt:OS_FM_TAB_MAX); - - result = __osst_write_header(STp, aSRpnt, 0xbae, 5); - if (STp->update_frame_cntr == 0) - osst_write_filler(STp, aSRpnt, 0xbb3, 5); - result &= __osst_write_header(STp, aSRpnt, 5, 5); - - if (locate_eod) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos); -#endif - osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0); - } - if (result) - printk(KERN_ERR "%s:E: Write header failed\n", name); - else { - memcpy(STp->application_sig, "LIN4", 4); - STp->linux_media = 1; - STp->linux_media_version = 4; - STp->header_ok = 1; - } - return result; -} - -static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - if (STp->header_cache != NULL) - memset(STp->header_cache, 0, sizeof(os_header_t)); - - STp->logical_blk_num = STp->frame_seq_number = 0; - STp->frame_in_buffer = 0; - STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A; - STp->filemark_cnt = 0; - STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; - return osst_write_header(STp, aSRpnt, 1); -} - -static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos) -{ - char * name = tape_name(STp); - os_header_t * header; - os_aux_t * aux; - char id_string[8]; - int linux_media_version, - update_frame_cntr; - - if (STp->raw) - return 1; - - if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) { - if (osst_set_frame_position(STp, aSRpnt, ppos, 0)) - printk(KERN_WARNING "%s:W: Couldn't position tape\n", name); - osst_wait_ready(STp, aSRpnt, 60 * 15, 0); - if (osst_initiate_read (STp, aSRpnt)) { - printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name); - return 0; - } - } - if (osst_read_frame(STp, aSRpnt, 180)) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name); -#endif - return 0; - } - header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */ - aux = STp->buffer->aux; - if (aux->frame_type != OS_FRAME_TYPE_HEADER) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos); -#endif - return 0; - } - if (ntohl(aux->frame_seq_num) != 0 || - ntohl(aux->logical_blk_num) != 0 || - aux->partition.partition_num != OS_CONFIG_PARTITION || - ntohl(aux->partition.first_frame_ppos) != 0 || - ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name, - ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), - aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos), - ntohl(aux->partition.last_frame_ppos)); -#endif - return 0; - } - if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 && - strncmp(header->ident_str, "ADR-SEQ", 7) != 0) { - strlcpy(id_string, header->ident_str, 8); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string); -#endif - return 0; - } - update_frame_cntr = ntohl(aux->update_frame_cntr); - if (update_frame_cntr < STp->update_frame_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n", - name, ppos, update_frame_cntr, STp->update_frame_cntr); -#endif - return 0; - } - if (header->major_rev != 1 || header->minor_rev != 4 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", - name, (header->major_rev != 1 || header->minor_rev < 2 || - header->minor_rev > 4 )? "Invalid" : "Warning:", - header->major_rev, header->minor_rev); -#endif - if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4) - return 0; - } -#if DEBUG - if (header->pt_par_num != 1) - printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", - name, header->pt_par_num); -#endif - memcpy(id_string, aux->application_sig, 4); - id_string[4] = 0; - if (memcmp(id_string, "LIN", 3) == 0) { - STp->linux_media = 1; - linux_media_version = id_string[3] - '0'; - if (linux_media_version != 4) - printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n", - name, linux_media_version); - } else { - printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string); - return 0; - } - if (linux_media_version < STp->linux_media_version) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n", - name, ppos, linux_media_version); -#endif - return 0; - } - if (linux_media_version > STp->linux_media_version) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n", - name, ppos, linux_media_version); -#endif - memcpy(STp->application_sig, id_string, 5); - STp->linux_media_version = linux_media_version; - STp->update_frame_cntr = -1; - } - if (update_frame_cntr > STp->update_frame_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n", - name, ppos, update_frame_cntr); -#endif - if (STp->header_cache == NULL) { - if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); - return 0; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name); -#endif - } - osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache); - header = STp->header_cache; /* further accesses from cached (full) copy */ - - STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr); - STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos); - STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos); - STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb); - STp->filemark_cnt = ntohl(aux->filemark_cnt); - STp->first_mark_ppos = ntohl(aux->next_mark_ppos); - STp->last_mark_ppos = ntohl(aux->last_mark_ppos); - STp->last_mark_lbn = ntohl(aux->last_mark_lbn); - STp->update_frame_cntr = update_frame_cntr; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n", - name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); - printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name, - STp->first_data_ppos, - ntohl(header->partition[0].last_frame_ppos), - ntohl(header->partition[0].eod_frame_ppos)); - printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", - name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); -#endif - if (header->minor_rev < 4 && STp->linux_media_version == 4) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name); -#endif - memcpy((void *)header->dat_fm_tab.fm_tab_ent, - (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent)); - memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list)); - } - if (header->minor_rev == 4 && - (header->ext_trk_tb_off != htons(17192) || - header->partition[0].partition_num != OS_DATA_PARTITION || - header->partition[0].par_desc_ver != OS_PARTITION_VERSION || - header->partition[0].last_frame_ppos != htonl(STp->capacity) || - header->cfg_col_width != htonl(20) || - header->dat_col_width != htonl(1500) || - header->qfa_col_width != htonl(0) || - header->ext_track_tb.nr_stream_part != 1 || - header->ext_track_tb.et_ent_sz != 32 || - header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION || - header->ext_track_tb.dat_ext_trk_ey.fmt != 1 || - header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) || - header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 || - header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) || - header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION || - header->dat_fm_tab.fm_tab_ent_sz != 4 || - header->dat_fm_tab.fm_tab_ent_cnt != - htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX))) - printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name); - - } - - return 1; -} - -static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int position, ppos; - int first, last; - int valid = 0; - char * name = tape_name(STp); - - position = osst_get_frame_position(STp, aSRpnt); - - if (STp->raw) { - STp->header_ok = STp->linux_media = 1; - STp->linux_media_version = 0; - return 1; - } - STp->header_ok = STp->linux_media = STp->linux_media_version = 0; - STp->wrt_pass_cntr = STp->update_frame_cntr = -1; - STp->eod_frame_ppos = STp->first_data_ppos = -1; - STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reading header\n", name); -#endif - - /* optimization for speed - if we are positioned at ppos 10, read second group first */ - /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */ - - first = position==10?0xbae: 5; - last = position==10?0xbb3:10; - - for (ppos = first; ppos < last; ppos++) - if (__osst_analyze_headers(STp, aSRpnt, ppos)) - valid = 1; - - first = position==10? 5:0xbae; - last = position==10?10:0xbb3; - - for (ppos = first; ppos < last; ppos++) - if (__osst_analyze_headers(STp, aSRpnt, ppos)) - valid = 1; - - if (!valid) { - printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name); - STp->eod_frame_ppos = STp->first_data_ppos = 0; - osst_set_frame_position(STp, aSRpnt, 10, 0); - return 0; - } - if (position <= STp->first_data_ppos) { - position = STp->first_data_ppos; - STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; - } - osst_set_frame_position(STp, aSRpnt, position, 0); - STp->header_ok = 1; - - return 1; -} - -static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int frame_position = STp->first_frame_position; - int frame_seq_numbr = STp->frame_seq_number; - int logical_blk_num = STp->logical_blk_num; - int halfway_frame = STp->frame_in_buffer; - int read_pointer = STp->buffer->read_pointer; - int prev_mark_ppos = -1; - int actual_mark_ppos, i, n; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name); -#endif - osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name); -#endif - return (-EIO); - } - if (STp->linux_media_version >= 4) { - for (i=0; i<STp->filemark_cnt; i++) - if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position) - prev_mark_ppos = n; - } else - prev_mark_ppos = frame_position - 1; /* usually - we don't really know */ - actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ? - frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos); - if (frame_position != STp->first_frame_position || - frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) || - prev_mark_ppos != actual_mark_ppos ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name, - STp->first_frame_position, frame_position, - STp->frame_seq_number + (halfway_frame?0:1), - frame_seq_numbr, actual_mark_ppos, prev_mark_ppos); -#endif - return (-EIO); - } - if (halfway_frame) { - /* prepare buffer for append and rewrite on top of original */ - osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); - STp->buffer->buffer_bytes = read_pointer; - STp->ps[STp->partition].rw = ST_WRITING; - STp->dirty = 1; - } - STp->frame_in_buffer = halfway_frame; - STp->frame_seq_number = frame_seq_numbr; - STp->logical_blk_num = logical_blk_num; - return 0; -} - -/* Acc. to OnStream, the vers. numbering is the following: - * X.XX for released versions (X=digit), - * XXXY for unreleased versions (Y=letter) - * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06 - * This fn makes monoton numbers out of this scheme ... - */ -static unsigned int osst_parse_firmware_rev (const char * str) -{ - if (str[1] == '.') { - return (str[0]-'0')*10000 - +(str[2]-'0')*1000 - +(str[3]-'0')*100; - } else { - return (str[0]-'0')*10000 - +(str[1]-'0')*1000 - +(str[2]-'0')*100 - 100 - +(str[3]-'@'); - } -} - -/* - * Configure the OnStream SCII tape drive for default operation - */ -static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - char * name = tape_name(STp); - struct osst_request * SRpnt = * aSRpnt; - osst_mode_parameter_header_t * header; - osst_block_size_page_t * bs; - osst_capabilities_page_t * cp; - osst_tape_paramtr_page_t * prm; - int drive_buffer_size; - - if (STp->ready != ST_READY) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Not Ready\n", name); -#endif - return (-EIO); - } - - if (STp->os_fw_rev < 10600) { - printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev); - printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name); - } - - /* - * Configure 32.5KB (data+aux) frame size. - * Get the current frame size from the block size mode page - */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = BLOCK_SIZE_PAGE; - cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - if (SRpnt == NULL) { -#if DEBUG - printk(OSST_DEB_MSG "osst :D: Busy\n"); -#endif - return (-EBUSY); - } - *aSRpnt = SRpnt; - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No"); -#endif - - /* - * Configure default auto columns mode, 32.5KB transfer mode - */ - bs->one = 1; - bs->play32 = 0; - bs->play32_5 = 1; - bs->record32 = 0; - bs->record32_5 = 1; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name); - return (-EIO); - } - -#if DEBUG - printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name); - /* - * In debug mode, we want to see as many errors as possible - * to test the error recovery mechanism. - */ - osst_set_retries(STp, aSRpnt, 0); - SRpnt = * aSRpnt; -#endif - - /* - * Set vendor name to 'LIN4' for "Linux support version 4". - */ - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; - - header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1; - header->medium_type = 0; /* Medium Type - ignoring */ - header->dsp = 0; /* Reserved */ - header->bdl = 0; /* Block Descriptor Length */ - - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7); - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, - (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2)); - return (-EIO); - } - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = CAPABILITIES_PAGE; - cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get capabilities page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data + - sizeof(osst_mode_parameter_header_t) + header->bdl); - - drive_buffer_size = ntohs(cp->buffer_size) / 2; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = TAPE_PARAMTR_PAGE; - cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data + - sizeof(osst_mode_parameter_header_t) + header->bdl); - - STp->density = prm->density; - STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n", - name, STp->density, STp->capacity / 32, drive_buffer_size); -#endif - - return 0; - -} - - -/* Step over EOF if it has been inadvertently crossed (ioctl not used because - it messes up the block number). */ -static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward) -{ - int result; - char * name = tape_name(STp); - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n", - name, forward ? "forward" : "backward"); -#endif - - if (forward) { - /* assumes that the filemark is already read by the drive, so this is low cost */ - result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1); - } - else - /* assumes this is only called if we just read the filemark! */ - result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1); - - if (result < 0) - printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n", - name, forward ? "forward" : "backward"); - - return result; -} - - -/* Get the tape position. */ - -static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - unsigned char scmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int result = 0; - char * name = tape_name(STp); - - /* KG: We want to be able to use it for checking Write Buffer availability - * and thus don't want to risk to overwrite anything. Exchange buffers ... */ - char mybuf[24]; - char * olddata = STp->buffer->b_data; - int oldsize = STp->buffer->buffer_size; - - if (STp->ready != ST_READY) return (-EIO); - - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = READ_POSITION; - - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - if (!SRpnt) { - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - return (-EBUSY); - } - *aSRpnt = SRpnt; - - if (STp->buffer->syscall_result) - result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */ - - if (result == -EINVAL) - printk(KERN_ERR "%s:E: Can't read tape position.\n", name); - else { - if (result == -EIO) { /* re-read position - this needs to preserve media errors */ - unsigned char mysense[16]; - memcpy (mysense, SRpnt->sense, 16); - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = READ_POSITION; - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n", - name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:", - SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]); -#endif - if (!STp->buffer->syscall_result) - memcpy (SRpnt->sense, mysense, 16); - else - printk(KERN_WARNING "%s:W: Double error in get position\n", name); - } - STp->first_frame_position = ((STp->buffer)->b_data[4] << 24) - + ((STp->buffer)->b_data[5] << 16) - + ((STp->buffer)->b_data[6] << 8) - + (STp->buffer)->b_data[7]; - STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24) - + ((STp->buffer)->b_data[ 9] << 16) - + ((STp->buffer)->b_data[10] << 8) - + (STp->buffer)->b_data[11]; - STp->cur_frames = (STp->buffer)->b_data[15]; -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name, - STp->first_frame_position, STp->last_frame_position, - ((STp->buffer)->b_data[0]&0x80)?" (BOP)": - ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"", - STp->cur_frames); - } -#endif - if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name, - STp->first_frame_position, STp->last_frame_position, STp->cur_frames); -#endif - STp->first_frame_position = STp->last_frame_position; - } - } - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - - return (result == 0 ? STp->first_frame_position : result); -} - - -/* Set the tape block */ -static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip) -{ - unsigned char scmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - struct st_partstat * STps; - int result = 0; - int pp = (ppos == 3000 && !skip)? 0 : ppos; - char * name = tape_name(STp); - - if (STp->ready != ST_READY) return (-EIO); - - STps = &(STp->ps[STp->partition]); - - if (ppos < 0 || ppos > STp->capacity) { - printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos); - pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1); - result = (-EINVAL); - } - - do { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp); -#endif - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = SEEK_10; - scmd[1] = 1; - scmd[3] = (pp >> 24); - scmd[4] = (pp >> 16); - scmd[5] = (pp >> 8); - scmd[6] = pp; - if (skip) - scmd[9] = 0x80; - - SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout, - MAX_RETRIES, 1); - if (!SRpnt) - return (-EBUSY); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n", - name, STp->first_frame_position, pp); -#endif - result = (-EIO); - } - if (pp != ppos) - osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); - } while ((pp != ppos) && (pp = ppos)); - STp->first_frame_position = STp->last_frame_position = ppos; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->rw = ST_IDLE; - STp->frame_in_buffer = 0; - return result; -} - -static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - int result = 0; - - if (STp->write_type != OS_WRITE_NEW_MARK) { - /* true unless the user wrote the filemark for us */ - result = osst_flush_drive_buffer(STp, aSRpnt); - if (result < 0) goto out; - result = osst_write_filemark(STp, aSRpnt); - if (result < 0) goto out; - - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - } - result = osst_write_eod(STp, aSRpnt); - osst_write_header(STp, aSRpnt, leave_at_EOT); - - STps->eof = ST_FM; -out: - return result; -} - -/* osst versions of st functions - augmented and stripped to suit OnStream only */ - -/* Flush the write buffer (never need to write if variable blocksize). */ -static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - int offset, transfer, blks = 0; - int result = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = *aSRpnt; - struct st_partstat * STps; - char * name = tape_name(STp); - - if ((STp->buffer)->writing) { - if (SRpnt == (STp->buffer)->last_SRpnt) -#if DEBUG - { printk(OSST_DEB_MSG - "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name); -#endif - *aSRpnt = SRpnt = NULL; -#if DEBUG - } else if (SRpnt) - printk(OSST_DEB_MSG - "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name); -#endif - osst_write_behind_check(STp); - if ((STp->buffer)->syscall_result) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n", - name, (STp->buffer)->midlevel_result); -#endif - if ((STp->buffer)->midlevel_result == INT_MAX) - return (-ENOSPC); - return (-EIO); - } - } - - result = 0; - if (STp->dirty == 1) { - - STp->write_count++; - STps = &(STp->ps[STp->partition]); - STps->rw = ST_WRITING; - offset = STp->buffer->buffer_bytes; - blks = (offset + STp->block_size - 1) / STp->block_size; - transfer = OS_FRAME_SIZE; - - if (offset < OS_DATA_SIZE) - osst_zero_buffer_tail(STp->buffer); - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120)) - result = osst_recover_wait_frame(STp, aSRpnt, 1); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; - - switch (STp->write_type) { - case OS_WRITE_DATA: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", - name, blks, STp->frame_seq_number, - STp->logical_blk_num - blks, STp->logical_blk_num - 1); -#endif - osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, - STp->logical_blk_num - blks, STp->block_size, blks); - break; - case OS_WRITE_EOD: - osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++, - STp->logical_blk_num, 0, 0); - break; - case OS_WRITE_NEW_MARK: - osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++, - STp->logical_blk_num++, 0, blks=1); - break; - case OS_WRITE_HEADER: - osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0); - break; - default: /* probably FILLER */ - osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0); - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n", - name, offset, transfer, blks); -#endif - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return (-EBUSY); - - if ((STp->buffer)->syscall_result != 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", - name, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */ - (SRpnt->sense[2] & 0x0f) == NO_SENSE) { - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - result = (-ENOSPC); - } - else { - if (osst_write_error_recovery(STp, aSRpnt, 1)) { - printk(KERN_ERR "%s:E: Error on flush write.\n", name); - result = (-EIO); - } - } - STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */ - } - else { - STp->first_frame_position++; - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - } - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result); -#endif - return result; -} - - -/* Flush the tape buffer. The tape will be positioned correctly unless - seek_next is true. */ -static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next) -{ - struct st_partstat * STps; - int backspace = 0, result = 0; -#if DEBUG - char * name = tape_name(STp); -#endif - - /* - * If there was a bus reset, block further access - * to this device. - */ - if( STp->pos_unknown) - return (-EIO); - - if (STp->ready != ST_READY) - return 0; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */ - STp->write_type = OS_WRITE_DATA; - return osst_flush_write_buffer(STp, aSRpnt); - } - if (STp->block_size == 0) - return 0; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name); -#endif - - if (!STp->can_bsr) { - backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size - - ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ; - (STp->buffer)->buffer_bytes = 0; - (STp->buffer)->read_pointer = 0; - STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */ - } - - if (!seek_next) { - if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */ - if (!result) - STps->eof = ST_NOEOF; - else { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - } - if (!result && backspace > 0) /* TODO -- design and run a test case for this */ - result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace); - } - else if (STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - - return result; -} - -static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int blks; -#if DEBUG - char * name = tape_name(STp); -#endif - - if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name); -#endif - if (osst_flush_drive_buffer(STp, aSRpnt) < 0) { - return (-EIO); - } - /* error recovery may have bumped us past the header partition */ - if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8); - } - } - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120)) - if (osst_recover_wait_frame(STp, aSRpnt, 1)) - return (-EIO); - -// osst_build_stats(STp, &SRpnt); - - STp->ps[STp->partition].rw = ST_WRITING; - STp->write_type = OS_WRITE_DATA; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; /* one frame at a time... */ - blks = STp->buffer->buffer_bytes / STp->block_size; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, - STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1); -#endif - osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, - STp->logical_blk_num - blks, STp->block_size, blks); - -#if DEBUG - if (!synchronous) - STp->write_pending = 1; -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout, - MAX_RETRIES, synchronous); - if (!SRpnt) - return (-EBUSY); - *aSRpnt = SRpnt; - - if (synchronous) { - if (STp->buffer->syscall_result != 0) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Error on write:\n", name); -#endif - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x40)) { - if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW) - return (-ENOSPC); - } - else { - if (osst_write_error_recovery(STp, aSRpnt, 1)) - return (-EIO); - } - } - else - STp->first_frame_position++; - } - - STp->write_count++; - - return 0; -} - -/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */ -static int do_door_lock(struct osst_tape * STp, int do_lock) -{ - int retval; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl"); -#endif - - retval = scsi_set_medium_removal(STp->device, - do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); - if (!retval) - STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; - else - STp->door_locked = ST_LOCK_FAILS; - return retval; -} - -/* Set the internal state after reset */ -static void reset_state(struct osst_tape *STp) -{ - int i; - struct st_partstat *STps; - - STp->pos_unknown = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = -1; - STps->drv_file = -1; - } -} - - -/* Entry points to osst */ - -/* Write command */ -static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos) -{ - ssize_t total, retval = 0; - ssize_t i, do_count, blks, transfer; - int write_threshold; - int doing_write = 0; - const char __user * b_point; - struct osst_request * SRpnt = NULL; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_tape * STp = filp->private_data; - char * name = tape_name(STp); - - - if (mutex_lock_interruptible(&STp->lock)) - return (-ERESTARTSYS); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - if (count == 0) - goto out; - - /* - * If there was a bus reset, block further access - * to this device. - */ - if (STp->pos_unknown) { - retval = (-EIO); - goto out; - } - -#if DEBUG - if (!STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - - if (STp->write_prot) { - retval = (-EACCES); - goto out; - } - - /* Write must be integral number of blocks */ - if (STp->block_size != 0 && (count % STp->block_size) != 0) { - printk(KERN_ERR "%s:E: Write (%zd bytes) not multiple of tape block size (%d%c).\n", - name, count, STp->block_size<1024? - STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); - retval = (-EINVAL); - goto out; - } - - if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) { - printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n", - name, STp->first_frame_position); - retval = (-ENOSPC); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - - if (STps->rw == ST_READING) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name, - STps->drv_file, STps->drv_block); -#endif - retval = osst_flush_buffer(STp, &SRpnt, 0); - if (retval) - goto out; - STps->rw = ST_IDLE; - } - if (STps->rw != ST_WRITING) { - /* Are we totally rewriting this tape? */ - if (!STp->header_ok || - (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) || - (STps->drv_file == 0 && STps->drv_block == 0)) { - STp->wrt_pass_cntr++; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n", - name, STp->wrt_pass_cntr); -#endif - osst_reset_header(STp, &SRpnt); - STps->drv_file = STps->drv_block = 0; - } - /* Do we know where we'll be writing on the tape? */ - else { - if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) || - STps->drv_file < 0 || STps->drv_block < 0) { - if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */ - STps->drv_file = STp->filemark_cnt; - STps->drv_block = 0; - } - else { - /* We have no idea where the tape is positioned - give up */ -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Cannot write at indeterminate position.\n", name); -#endif - retval = (-EIO); - goto out; - } - } - if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) { - STp->filemark_cnt = STps->drv_file; - STp->last_mark_ppos = - ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]); - printk(KERN_WARNING - "%s:W: Overwriting file %d with old write pass counter %d\n", - name, STps->drv_file, STp->wrt_pass_cntr); - printk(KERN_WARNING - "%s:W: may lead to stale data being accepted on reading back!\n", - name); -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n", - name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn); -#endif - } - } - STp->fast_open = 0; - } - if (!STp->header_ok) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name); -#endif - retval = (-EIO); - goto out; - } - - if ((STp->buffer)->writing) { -if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__); - osst_write_behind_check(STp); - if ((STp->buffer)->syscall_result) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name, - (STp->buffer)->midlevel_result); -#endif - if ((STp->buffer)->midlevel_result == INT_MAX) - STps->eof = ST_EOM_OK; - else - STps->eof = ST_EOM_ERROR; - } - } - if (STps->eof == ST_EOM_OK) { - retval = (-ENOSPC); - goto out; - } - else if (STps->eof == ST_EOM_ERROR) { - retval = (-EIO); - goto out; - } - - /* Check the buffer readability in cases where copy_user might catch - the problems after some tape movement. */ - if ((copy_from_user(&i, buf, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0)) { - retval = (-EFAULT); - goto out; - } - - if (!STm->do_buffer_writes) { - write_threshold = 1; - } - else - write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; - if (!STm->do_async_writes) - write_threshold--; - - total = count; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n", - name, (int) count, STps->drv_file, STps->drv_block, - STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position); -#endif - b_point = buf; - while ((STp->buffer)->buffer_bytes + count > write_threshold) - { - doing_write = 1; - do_count = (STp->buffer)->buffer_blocks * STp->block_size - - (STp->buffer)->buffer_bytes; - if (do_count > count) - do_count = count; - - i = append_to_buffer(b_point, STp->buffer, do_count); - if (i) { - retval = i; - goto out; - } - - blks = do_count / STp->block_size; - STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */ - - i = osst_write_frame(STp, &SRpnt, 1); - - if (i == (-ENOSPC)) { - transfer = STp->buffer->writing; /* FIXME -- check this logic */ - if (transfer <= do_count) { - *ppos += do_count - transfer; - count -= do_count - transfer; - if (STps->drv_block >= 0) { - STps->drv_block += (do_count - transfer) / STp->block_size; - } - STps->eof = ST_EOM_OK; - retval = (-ENOSPC); /* EOM within current request */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n", - name, (int) transfer); -#endif - } - else { - STps->eof = ST_EOM_ERROR; - STps->drv_block = (-1); /* Too cautious? */ - retval = (-EIO); /* EOM for old data */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name); -#endif - } - } - else - retval = i; - - if (retval < 0) { - if (SRpnt != NULL) { - osst_release_request(SRpnt); - SRpnt = NULL; - } - STp->buffer->buffer_bytes = 0; - STp->dirty = 0; - if (count < total) - retval = total - count; - goto out; - } - - *ppos += do_count; - b_point += do_count; - count -= do_count; - if (STps->drv_block >= 0) { - STps->drv_block += blks; - } - STp->buffer->buffer_bytes = 0; - STp->dirty = 0; - } /* end while write threshold exceeded */ - - if (count != 0) { - STp->dirty = 1; - i = append_to_buffer(b_point, STp->buffer, count); - if (i) { - retval = i; - goto out; - } - blks = count / STp->block_size; - STp->logical_blk_num += blks; - if (STps->drv_block >= 0) { - STps->drv_block += blks; - } - *ppos += count; - count = 0; - } - - if (doing_write && (STp->buffer)->syscall_result != 0) { - retval = (STp->buffer)->syscall_result; - goto out; - } - - if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { - /* Schedule an asynchronous write */ - (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / - STp->block_size) * STp->block_size; - STp->dirty = !((STp->buffer)->writing == - (STp->buffer)->buffer_bytes); - - i = osst_write_frame(STp, &SRpnt, 0); - if (i < 0) { - retval = (-EIO); - goto out; - } - SRpnt = NULL; /* Prevent releasing this request! */ - } - STps->at_sm &= (total == 0); - if (total > 0) - STps->eof = ST_NOEOF; - - retval = total; - -out: - if (SRpnt != NULL) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - return retval; -} - - -/* Read command */ -static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos) -{ - ssize_t total, retval = 0; - ssize_t i, transfer; - int special; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp = filp->private_data; - char * name = tape_name(STp); - - - if (mutex_lock_interruptible(&STp->lock)) - return (-ERESTARTSYS); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } -#if DEBUG - if (!STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - /* Must have initialized medium */ - if (!STp->header_ok) { - retval = (-EIO); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) { - retval = osst_flush_buffer(STp, &SRpnt, 0); - if (retval) - goto out; - STps->rw = ST_IDLE; - /* FIXME -- this may leave the tape without EOD and up2date headers */ - } - - if ((count % STp->block_size) != 0) { - printk(KERN_WARNING - "%s:W: Read (%zd bytes) not multiple of tape block size (%d%c).\n", name, count, - STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); - } - -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name, - STps->eof, (STp->buffer)->buffer_bytes); -#endif - if ((STp->buffer)->buffer_bytes == 0 && - STps->eof >= ST_EOD_1) { - if (STps->eof < ST_EOD) { - STps->eof += 1; - retval = 0; - goto out; - } - retval = (-EIO); /* EOM or Blank Check */ - goto out; - } - - /* Check the buffer writability before any tape movement. Don't alter - buffer data. */ - if (copy_from_user(&i, buf, 1) != 0 || - copy_to_user (buf, &i, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0 || - copy_to_user (buf + count - 1, &i, 1) != 0) { - retval = (-EFAULT); - goto out; - } - - /* Loop until enough data in buffer or a special condition found */ - for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) { - - /* Get new data if the buffer is empty */ - if ((STp->buffer)->buffer_bytes == 0) { - if (STps->eof == ST_FM_HIT) - break; - special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0); - if (special < 0) { /* No need to continue read */ - STp->frame_in_buffer = 0; - retval = special; - goto out; - } - } - - /* Move the data from driver buffer to user buffer */ - if ((STp->buffer)->buffer_bytes > 0) { -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name, - STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total)); -#endif - /* force multiple of block size, note block_size may have been adjusted */ - transfer = (((STp->buffer)->buffer_bytes < count - total ? - (STp->buffer)->buffer_bytes : count - total)/ - STp->block_size) * STp->block_size; - - if (transfer == 0) { - printk(KERN_WARNING - "%s:W: Nothing can be transferred, requested %zd, tape block size (%d%c).\n", - name, count, STp->block_size < 1024? - STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); - break; - } - i = from_buffer(STp->buffer, buf, transfer); - if (i) { - retval = i; - goto out; - } - STp->logical_blk_num += transfer / STp->block_size; - STps->drv_block += transfer / STp->block_size; - *ppos += transfer; - buf += transfer; - total += transfer; - } - - if ((STp->buffer)->buffer_bytes == 0) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n", - name, STp->frame_seq_number); -#endif - STp->frame_in_buffer = 0; - STp->frame_seq_number++; /* frame to look for next time */ - } - } /* for (total = 0, special = 0; total < count && !special; ) */ - - /* Change the eof state if no data from tape or buffer */ - if (total == 0) { - if (STps->eof == ST_FM_HIT) { - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } - else if (STps->eof == ST_EOD_1) { - STps->eof = ST_EOD_2; - if (STps->drv_block > 0 && STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - else if (STps->eof == ST_EOD_2) - STps->eof = ST_EOD; - } - else if (STps->eof == ST_FM) - STps->eof = ST_NOEOF; - - retval = total; - -out: - if (SRpnt != NULL) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - return retval; -} - - -/* Set the driver options */ -static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name) -{ - printk(KERN_INFO -"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STm->do_read_ahead); - printk(KERN_INFO -"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); - printk(KERN_INFO -"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, - STp->scsi2_logical); - printk(KERN_INFO -"%s:I: sysv: %d\n", name, STm->sysv); -#if DEBUG - printk(KERN_INFO - "%s:D: debugging: %d\n", - name, debugging); -#endif -} - - -static int osst_set_options(struct osst_tape *STp, long options) -{ - int value; - long code; - struct st_modedef * STm; - char * name = tape_name(STp); - - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - memcpy(STm, &(STp->modes[0]), sizeof(*STm)); - modes_defined = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n", - name, STp->current_mode); -#endif - } - - code = options & MT_ST_OPTIONS; - if (code == MT_ST_BOOLEANS) { - STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; - STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; - STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; - STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; - STp->two_fm = (options & MT_ST_TWO_FM) != 0; - STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; - STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; - STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; - STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; - if ((STp->device)->scsi_level >= SCSI_2) - STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; - STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; - STm->sysv = (options & MT_ST_SYSV) != 0; -#if DEBUG - debugging = (options & MT_ST_DEBUGGING) != 0; -#endif - osst_log_options(STp, STm, name); - } - else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { - value = (code == MT_ST_SETBOOLEANS); - if ((options & MT_ST_BUFFER_WRITES) != 0) - STm->do_buffer_writes = value; - if ((options & MT_ST_ASYNC_WRITES) != 0) - STm->do_async_writes = value; - if ((options & MT_ST_DEF_WRITES) != 0) - STm->defaults_for_writes = value; - if ((options & MT_ST_READ_AHEAD) != 0) - STm->do_read_ahead = value; - if ((options & MT_ST_TWO_FM) != 0) - STp->two_fm = value; - if ((options & MT_ST_FAST_MTEOM) != 0) - STp->fast_mteom = value; - if ((options & MT_ST_AUTO_LOCK) != 0) - STp->do_auto_lock = value; - if ((options & MT_ST_CAN_BSR) != 0) - STp->can_bsr = value; - if ((options & MT_ST_NO_BLKLIMS) != 0) - STp->omit_blklims = value; - if ((STp->device)->scsi_level >= SCSI_2 && - (options & MT_ST_CAN_PARTITIONS) != 0) - STp->can_partitions = value; - if ((options & MT_ST_SCSI2LOGICAL) != 0) - STp->scsi2_logical = value; - if ((options & MT_ST_SYSV) != 0) - STm->sysv = value; -#if DEBUG - if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; -#endif - osst_log_options(STp, STm, name); - } - else if (code == MT_ST_WRITE_THRESHOLD) { - value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; - if (value < 1 || value > osst_buffer_size) { - printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n", - name, value); - return (-EIO); - } - STp->write_threshold = value; - printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n", - name, value); - } - else if (code == MT_ST_DEF_BLKSIZE) { - value = (options & ~MT_ST_OPTIONS); - if (value == ~MT_ST_OPTIONS) { - STm->default_blksize = (-1); - printk(KERN_INFO "%s:I: Default block size disabled.\n", name); - } - else { - if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) { - printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n", - name, value); - return (-EINVAL); - } - STm->default_blksize = value; - printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n", - name, STm->default_blksize); - } - } - else if (code == MT_ST_TIMEOUTS) { - value = (options & ~MT_ST_OPTIONS); - if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { - STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name, - (value & ~MT_ST_SET_LONG_TIMEOUT)); - } - else { - STp->timeout = value * HZ; - printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value); - } - } - else if (code == MT_ST_DEF_OPTIONS) { - code = (options & ~MT_ST_CLEAR_DEFAULT); - value = (options & MT_ST_CLEAR_DEFAULT); - if (code == MT_ST_DEF_DENSITY) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_density = (-1); - printk(KERN_INFO "%s:I: Density default disabled.\n", name); - } - else { - STm->default_density = value & 0xff; - printk(KERN_INFO "%s:I: Density default set to %x\n", - name, STm->default_density); - } - } - else if (code == MT_ST_DEF_DRVBUFFER) { - if (value == MT_ST_CLEAR_DEFAULT) { - STp->default_drvbuffer = 0xff; - printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name); - } - else { - STp->default_drvbuffer = value & 7; - printk(KERN_INFO "%s:I: Drive buffer default set to %x\n", - name, STp->default_drvbuffer); - } - } - else if (code == MT_ST_DEF_COMPRESSION) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO "%s:I: Compression default disabled.\n", name); - } - else { - STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "%s:I: Compression default set to %x\n", - name, (value & 1)); - } - } - } - else - return (-EIO); - - return 0; -} - - -/* Internal ioctl function */ -static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int cmd_in, unsigned long arg) -{ - int timeout; - long ltmp; - int i, ioctl_result; - int chg_eof = 1; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = * aSRpnt; - struct st_partstat * STps; - int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num; - int datalen = 0, direction = DMA_NONE; - char * name = tape_name(STp); - - if (STp->ready != ST_READY && cmd_in != MTLOAD) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm = STps->at_sm; - frame_seq_numbr = STp->frame_seq_number; - logical_blk_num = STp->logical_blk_num; - - memset(cmd, 0, MAX_COMMAND_SIZE); - switch (cmd_in) { - case MTFSFM: - chg_eof = 0; /* Changed from the FSF after this */ - case MTFSF: - if (STp->raw) - return (-EIO); - if (STp->linux_media) - ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg); - else - ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg); - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm &= (arg == 0); - goto os_bypass; - - case MTBSF: - chg_eof = 0; /* Changed from the FSF after this */ - case MTBSFM: - if (STp->raw) - return (-EIO); - ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg); - if (fileno >= 0) - fileno -= arg; - blkno = (-1); /* We can't know the block number */ - at_sm &= (arg == 0); - goto os_bypass; - - case MTFSR: - case MTBSR: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n", - name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); -#endif - if (cmd_in == MTFSR) { - logical_blk_num += arg; - if (blkno >= 0) blkno += arg; - } - else { - logical_blk_num -= arg; - if (blkno >= 0) blkno -= arg; - } - ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm &= (arg == 0); - goto os_bypass; - - case MTFSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTBSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n", - name, (-ltmp)); - } -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTWEOF: - if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { - STp->write_type = OS_WRITE_DATA; - ioctl_result = osst_flush_write_buffer(STp, &SRpnt); - } else - ioctl_result = 0; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg); -#endif - for (i=0; i<arg; i++) - ioctl_result |= osst_write_filemark(STp, &SRpnt); - if (fileno >= 0) fileno += arg; - if (blkno >= 0) blkno = 0; - goto os_bypass; - - case MTWSM: - if (STp->write_prot) - return (-EACCES); - if (!STp->raw) - return 0; - cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */ - if (cmd_in == MTWSM) - cmd[1] = 2; - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - timeout = STp->timeout; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm = (cmd_in == MTWSM); - break; - case MTOFFL: - case MTLOAD: - case MTUNLOAD: - case MTRETEN: - cmd[0] = START_STOP; - cmd[1] = 1; /* Don't wait for completion */ - if (cmd_in == MTLOAD) { - if (STp->ready == ST_NO_TAPE) - cmd[4] = 4; /* open tray */ - else - cmd[4] = 1; /* load */ - } - if (cmd_in == MTRETEN) - cmd[4] = 3; /* retension then mount */ - if (cmd_in == MTOFFL) - cmd[4] = 4; /* rewind then eject */ - timeout = STp->timeout; -#if DEBUG - if (debugging) { - switch (cmd_in) { - case MTUNLOAD: - printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name); - break; - case MTLOAD: - printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name); - break; - case MTRETEN: - printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name); - break; - case MTOFFL: - printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name); - break; - } - } -#endif - fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; - break; - case MTNOP: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name); -#endif - return 0; /* Should do something ? */ - break; - case MTEOM: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name); -#endif - if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) || - (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) { - ioctl_result = -EIO; - goto os_bypass; - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name); -#endif - ioctl_result = -EIO; - goto os_bypass; - } - ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0); - fileno = STp->filemark_cnt; - blkno = at_sm = 0; - goto os_bypass; - - case MTERASE: - if (STp->write_prot) - return (-EACCES); - ioctl_result = osst_reset_header(STp, &SRpnt); - i = osst_write_eod(STp, &SRpnt); - if (i < ioctl_result) ioctl_result = i; - i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos); - if (i < ioctl_result) ioctl_result = i; - fileno = blkno = at_sm = 0 ; - goto os_bypass; - - case MTREW: - cmd[0] = REZERO_UNIT; /* rewind */ - cmd[1] = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]); -#endif - fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; - break; - - case MTSETBLK: /* Set block length */ - if ((STps->drv_block == 0 ) && - !STp->dirty && - ((STp->buffer)->buffer_bytes == 0) && - ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) && - ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) && - !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) { - /* - * Only allowed to change the block size if you opened the - * device at the beginning of a file before writing anything. - * Note, that when reading, changing block_size is futile, - * as the size used when writing overrides it. - */ - STp->block_size = (arg & MT_ST_BLKSIZE_MASK); - printk(KERN_INFO "%s:I: Block size set to %d bytes.\n", - name, STp->block_size); - return 0; - } - case MTSETDENSITY: /* Set tape density */ - case MTSETDRVBUFFER: /* Set drive buffering */ - case SET_DENS_AND_BLK: /* Set density and block size */ - chg_eof = 0; - if (STp->dirty || (STp->buffer)->buffer_bytes != 0) - return (-EIO); /* Not allowed if data in buffer */ - if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && - (arg & MT_ST_BLKSIZE_MASK) != 0 && - (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) { - printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n", - name, (int)(arg & MT_ST_BLKSIZE_MASK), - (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now"); - return (-EINVAL); - } - return 0; /* FIXME silently ignore if block size didn't change */ - - default: - return (-ENOSYS); - } - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1); - - ioctl_result = (STp->buffer)->syscall_result; - - if (!SRpnt) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name); -#endif - return ioctl_result; - } - - if (!ioctl_result) { /* SCSI command successful */ - STp->frame_seq_number = frame_seq_numbr; - STp->logical_blk_num = logical_blk_num; - } - -os_bypass: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result); -#endif - - if (!ioctl_result) { /* success */ - - if (cmd_in == MTFSFM) { - fileno--; - blkno--; - } - if (cmd_in == MTBSFM) { - fileno++; - blkno++; - } - STps->drv_block = blkno; - STps->drv_file = fileno; - STps->at_sm = at_sm; - - if (cmd_in == MTEOM) - STps->eof = ST_EOD; - else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) { - ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1); - STps->drv_block++; - STp->logical_blk_num++; - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->read_pointer = 0; - } - else if (cmd_in == MTFSF) - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; - else if (chg_eof) - STps->eof = ST_NOEOF; - - if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) - STp->rew_at_close = 0; - else if (cmd_in == MTLOAD) { - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */ - } - STp->partition = 0; - } - - if (cmd_in == MTREW) { - ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); - if (ioctl_result > 0) - ioctl_result = 0; - } - - } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) { - if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0) - STps->drv_file = STps->drv_block = -1; - else - STps->drv_file = STps->drv_block = 0; - STps->eof = ST_NOEOF; - } else if (cmd_in == MTFSF || cmd_in == MTFSFM) { - if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) - STps->drv_file = STps->drv_block = -1; - else { - STps->drv_file = STp->filemark_cnt; - STps->drv_block = 0; - } - STps->eof = ST_EOD; - } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) { - STps->drv_file = STps->drv_block = (-1); - STps->eof = ST_NOEOF; - STp->header_ok = 0; - } else if (cmd_in == MTERASE) { - STp->header_ok = 0; - } else if (SRpnt) { /* SCSI command was not completely successful. */ - if (SRpnt->sense[2] & 0x40) { - STps->eof = ST_EOM_OK; - STps->drv_block = 0; - } - if (chg_eof) - STps->eof = ST_NOEOF; - - if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK) - STps->eof = ST_EOD; - - if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) - ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); - } - *aSRpnt = SRpnt; - - return ioctl_result; -} - - -/* Open the device */ -static int __os_scsi_tape_open(struct inode * inode, struct file * filp) -{ - unsigned short flags; - int i, b_size, new_session = 0, retval = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp; - struct st_modedef * STm; - struct st_partstat * STps; - char * name; - int dev = TAPE_NR(inode); - int mode = TAPE_MODE(inode); - - /* - * We really want to do nonseekable_open(inode, filp); here, but some - * versions of tar incorrectly call lseek on tapes and bail out if that - * fails. So we disallow pread() and pwrite(), but permit lseeks. - */ - filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - - write_lock(&os_scsi_tapes_lock); - if (dev >= osst_max_dev || os_scsi_tapes == NULL || - (STp = os_scsi_tapes[dev]) == NULL || !STp->device) { - write_unlock(&os_scsi_tapes_lock); - return (-ENXIO); - } - - name = tape_name(STp); - - if (STp->in_use) { - write_unlock(&os_scsi_tapes_lock); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name); -#endif - return (-EBUSY); - } - if (scsi_device_get(STp->device)) { - write_unlock(&os_scsi_tapes_lock); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name); -#endif - return (-ENXIO); - } - filp->private_data = STp; - STp->in_use = 1; - write_unlock(&os_scsi_tapes_lock); - STp->rew_at_close = TAPE_REWIND(inode); - - if( !scsi_block_when_processing_errors(STp->device) ) { - return -ENXIO; - } - - if (mode != STp->current_mode) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n", - name, STp->current_mode, mode); -#endif - new_session = 1; - STp->current_mode = mode; - } - STm = &(STp->modes[STp->current_mode]); - - flags = filp->f_flags; - STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); - - STp->raw = TAPE_IS_RAW(inode); - if (STp->raw) - STp->header_ok = 0; - - /* Allocate data segments for this device's tape buffer */ - if (!enlarge_buffer(STp->buffer, STp->restr_dma)) { - printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name); - retval = (-EOVERFLOW); - goto err_out; - } - if (STp->buffer->buffer_size >= OS_FRAME_SIZE) { - for (i = 0, b_size = 0; - (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); - b_size += STp->buffer->sg[i++].length); - STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name, - STp->buffer->b_data, page_address(STp->buffer->sg[0].page)); - printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name, - STp->buffer->aux, i, page_address(STp->buffer->sg[i].page)); -#endif - } else { - STp->buffer->aux = NULL; /* this had better never happen! */ - printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE); - retval = (-EIO); - goto err_out; - } - STp->buffer->writing = 0; - STp->buffer->syscall_result = 0; - STp->dirty = 0; - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->ready = ST_READY; -#if DEBUG - STp->nbr_waits = STp->nbr_finished = 0; -#endif - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - if (!SRpnt) { - retval = (STp->buffer)->syscall_result; /* FIXME - valid? */ - goto err_out; - } - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == NOT_READY && - SRpnt->sense[12] == 4 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]); -#endif - if (filp->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto err_out; - } - if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */ - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = START_STOP; - cmd[1] = 1; - cmd[4] = 1; - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - } - osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0); - } - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name); -#endif - STp->header_ok = 0; - - for (i=0; i < 10; i++) { - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - if ((SRpnt->sense[0] & 0x70) != 0x70 || - (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION) - break; - } - - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = 1; - STp->recover_count = 0; - STp->abort_count = 0; - } - /* - * if we have valid headers from before, and the drive/tape seem untouched, - * open without reconfiguring and re-reading the headers - */ - if (!STp->buffer->syscall_result && STp->header_ok && - !SRpnt->result && SRpnt->sense[0] == 0) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = VENDOR_IDENT_PAGE; - cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - - if (STp->buffer->syscall_result || - STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name, - STp->buffer->b_data[MODE_HEADER_LENGTH + 2], - STp->buffer->b_data[MODE_HEADER_LENGTH + 3], - STp->buffer->b_data[MODE_HEADER_LENGTH + 4], - STp->buffer->b_data[MODE_HEADER_LENGTH + 5]); -#endif - STp->header_ok = 0; - } - i = STp->first_frame_position; - if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) { - if (STp->door_locked == ST_UNLOCKED) { - if (do_door_lock(STp, 1)) - printk(KERN_INFO "%s:I: Can't lock drive door\n", name); - else - STp->door_locked = ST_LOCKED_AUTO; - } - if (!STp->frame_in_buffer) { - STp->block_size = (STm->default_blksize > 0) ? - STm->default_blksize : OS_DATA_SIZE; - STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; - } - STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; - STp->fast_open = 1; - osst_release_request(SRpnt); - return 0; - } -#if DEBUG - if (i != STp->first_frame_position) - printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n", - name, i, STp->first_frame_position); -#endif - STp->header_ok = 0; - } - STp->fast_open = 0; - - if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */ - (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = 4 + MODE_HEADER_LENGTH; - - (STp->buffer)->b_data[0] = cmd[4] - 1; - (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ - (STp->buffer)->b_data[2] = 0; /* Reserved */ - (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name); -#endif - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - - STp->header_ok = 0; - - for (i=0; i < 10; i++) { - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - if ((SRpnt->sense[0] & 0x70) != 0x70 || - (SRpnt->sense[2] & 0x0f) == NOT_READY) - break; - - if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { - int j; - - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (j = 0; j < ST_NBR_PARTITIONS; j++) { - STps = &(STp->ps[j]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = 1; - } - } - } - - if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */ - printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name); - - if ((STp->buffer)->syscall_result != 0) { - if ((STp->device)->scsi_level >= SCSI_2 && - (SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == NOT_READY && - SRpnt->sense[12] == 0x3a) { /* Check ASC */ - STp->ready = ST_NO_TAPE; - } else - STp->ready = ST_NOT_READY; - osst_release_request(SRpnt); - SRpnt = NULL; - STp->density = 0; /* Clear the erroneous "residue" */ - STp->write_prot = 0; - STp->block_size = 0; - STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); - STp->partition = STp->new_partition = 0; - STp->door_locked = ST_UNLOCKED; - return 0; - } - - osst_configure_onstream(STp, &SRpnt); - - STp->block_size = STp->raw ? OS_FRAME_SIZE : ( - (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); - STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; - STp->buffer->buffer_bytes = - STp->buffer->read_pointer = - STp->frame_in_buffer = 0; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", - name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, - (STp->buffer)->buffer_blocks); -#endif - - if (STp->drv_write_prot) { - STp->write_prot = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Write protected\n", name); -#endif - if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { - retval = (-EROFS); - goto err_out; - } - } - - if (new_session) { /* Change the drive parameters for the new mode */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: New Session\n", name); -#endif - STp->density_changed = STp->blksize_changed = 0; - STp->compression_changed = 0; - } - - /* - * properly position the tape and check the ADR headers - */ - if (STp->door_locked == ST_UNLOCKED) { - if (do_door_lock(STp, 1)) - printk(KERN_INFO "%s:I: Can't lock drive door\n", name); - else - STp->door_locked = ST_LOCKED_AUTO; - } - - osst_analyze_headers(STp, &SRpnt); - - osst_release_request(SRpnt); - SRpnt = NULL; - - return 0; - -err_out: - if (SRpnt != NULL) - osst_release_request(SRpnt); - normalize_buffer(STp->buffer); - STp->header_ok = 0; - STp->in_use = 0; - scsi_device_put(STp->device); - - return retval; -} - -/* BKL pushdown: spaghetti avoidance wrapper */ -static int os_scsi_tape_open(struct inode * inode, struct file * filp) -{ - int ret; - - mutex_lock(&osst_int_mutex); - ret = __os_scsi_tape_open(inode, filp); - mutex_unlock(&osst_int_mutex); - return ret; -} - - - -/* Flush the tape buffer before close */ -static int os_scsi_tape_flush(struct file * filp, fl_owner_t id) -{ - int result = 0, result2; - struct osst_tape * STp = filp->private_data; - struct st_modedef * STm = &(STp->modes[STp->current_mode]); - struct st_partstat * STps = &(STp->ps[STp->partition]); - struct osst_request * SRpnt = NULL; - char * name = tape_name(STp); - - if (file_count(filp) > 1) - return 0; - - if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { - STp->write_type = OS_WRITE_DATA; - result = osst_flush_write_buffer(STp, &SRpnt); - if (result != 0 && result != (-ENOSPC)) - goto out; - } - if ( STps->rw >= ST_WRITING && !STp->pos_unknown) { - -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n", - name, (long)(filp->f_pos)); - printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n", - name, STp->nbr_waits, STp->nbr_finished); - } -#endif - result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close)); -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n", - name, 1+STp->two_fm); -#endif - } - else if (!STp->rew_at_close) { - STps = &(STp->ps[STp->partition]); - if (!STm->sysv || STps->rw != ST_READING) { - if (STp->can_bsr) - result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */ - else if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, &SRpnt, 0); - if (result) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - else - STps->eof = ST_NOEOF; - } - } - else if ((STps->eof == ST_NOEOF && - !(result = cross_eof(STp, &SRpnt, 1))) || - STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - } - -out: - if (STp->rew_at_close) { - result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); - STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; - if (result == 0 && result2 < 0) - result = result2; - } - if (SRpnt) osst_release_request(SRpnt); - - if (STp->abort_count || STp->recover_count) { - printk(KERN_INFO "%s:I:", name); - if (STp->abort_count) - printk(" %d unrecovered errors", STp->abort_count); - if (STp->recover_count) - printk(" %d recovered errors", STp->recover_count); - if (STp->write_count) - printk(" in %d frames written", STp->write_count); - if (STp->read_count) - printk(" in %d frames read", STp->read_count); - printk("\n"); - STp->recover_count = 0; - STp->abort_count = 0; - } - STp->write_count = 0; - STp->read_count = 0; - - return result; -} - - -/* Close the device and release it */ -static int os_scsi_tape_close(struct inode * inode, struct file * filp) -{ - int result = 0; - struct osst_tape * STp = filp->private_data; - - if (STp->door_locked == ST_LOCKED_AUTO) - do_door_lock(STp, 0); - - if (STp->raw) - STp->header_ok = 0; - - normalize_buffer(STp->buffer); - write_lock(&os_scsi_tapes_lock); - STp->in_use = 0; - write_unlock(&os_scsi_tapes_lock); - - scsi_device_put(STp->device); - - return result; -} - - -/* The ioctl command */ -static long osst_ioctl(struct file * file, - unsigned int cmd_in, unsigned long arg) -{ - int i, cmd_nr, cmd_type, blk, retval = 0; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp = file->private_data; - char * name = tape_name(STp); - void __user * p = (void __user *)arg; - - mutex_lock(&osst_int_mutex); - if (mutex_lock_interruptible(&STp->lock)) { - mutex_unlock(&osst_int_mutex); - return -ERESTARTSYS; - } - -#if DEBUG - if (debugging && !STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in, - file->f_flags & O_NDELAY); - if (retval) - goto out; - - cmd_type = _IOC_TYPE(cmd_in); - cmd_nr = _IOC_NR(cmd_in); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name, - cmd_type, cmd_nr, STp->raw?"raw":"normal"); -#endif - if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { - struct mtop mtc; - int auto_weof = 0; - - if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { - retval = (-EINVAL); - goto out; - } - - i = copy_from_user((char *) &mtc, p, sizeof(struct mtop)); - if (i) { - retval = (-EFAULT); - goto out; - } - - if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name); - retval = (-EPERM); - goto out; - } - - if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) { - retval = (-ENXIO); - goto out; - } - - if (!STp->pos_unknown) { - - if (STps->eof == ST_FM_HIT) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { - mtc.mt_count -= 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { - mtc.mt_count += 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - } - - if (mtc.mt_op == MTSEEK) { - /* Old position must be restored if partition will be changed */ - i = !STp->can_partitions || (STp->new_partition != STp->partition); - } - else { - i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || - mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || - mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || - mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || - mtc.mt_op == MTCOMPRESSION; - } - i = osst_flush_buffer(STp, &SRpnt, i); - if (i < 0) { - retval = i; - goto out; - } - } - else { - /* - * If there was a bus reset, block further access - * to this device. If the user wants to rewind the tape, - * then reset the flag and allow access again. - */ - if(mtc.mt_op != MTREW && - mtc.mt_op != MTOFFL && - mtc.mt_op != MTRETEN && - mtc.mt_op != MTERASE && - mtc.mt_op != MTSEEK && - mtc.mt_op != MTEOM) { - retval = (-EIO); - goto out; - } - reset_state(STp); - /* remove this when the midlevel properly clears was_reset */ - STp->device->was_reset = 0; - } - - if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK && - mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER && - mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART && - mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) { - - /* - * The user tells us to move to another position on the tape. - * If we were appending to the tape content, that would leave - * the tape without proper end, in that case write EOD and - * update the header to reflect its position. - */ -#if DEBUG - printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name, - STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle", - STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number, - STp->logical_blk_num, STps->drv_file, STps->drv_block ); -#endif - if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) { - auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) && - !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); - i = osst_write_trailer(STp, &SRpnt, - !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); -#if DEBUG - printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", - name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos, - STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block ); -#endif - if (i < 0) { - retval = i; - goto out; - } - } - STps->rw = ST_IDLE; - } - - if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) - do_door_lock(STp, 0); /* Ignore result! */ - - if (mtc.mt_op == MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) != 0) { - retval = osst_set_options(STp, mtc.mt_count); - goto out; - } - - if (mtc.mt_op == MTSETPART) { - if (mtc.mt_count >= STp->nbr_partitions) - retval = -EINVAL; - else { - STp->new_partition = mtc.mt_count; - retval = 0; - } - goto out; - } - - if (mtc.mt_op == MTMKPART) { - if (!STp->can_partitions) { - retval = (-EINVAL); - goto out; - } - if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*|| - (i = partition_tape(inode, mtc.mt_count)) < 0*/) { - retval = i; - goto out; - } - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].at_sm = 0; - STp->ps[i].last_block_valid = 0; - } - STp->partition = STp->new_partition = 0; - STp->nbr_partitions = 1; /* Bad guess ?-) */ - STps->drv_block = STps->drv_file = 0; - retval = 0; - goto out; - } - - if (mtc.mt_op == MTSEEK) { - if (STp->raw) - i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); - else - i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); - if (!STp->can_partitions) - STp->ps[0].rw = ST_IDLE; - retval = i; - goto out; - } - - if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { - retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); - goto out; - } - - if (auto_weof) - cross_eof(STp, &SRpnt, 0); - - if (mtc.mt_op == MTCOMPRESSION) - retval = -EINVAL; /* OnStream drives don't have compression hardware */ - else - /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS - * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */ - retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count); - goto out; - } - - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - - if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) { - retval = i; - goto out; - } - - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { - struct mtget mt_status; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { - retval = (-EINVAL); - goto out; - } - - mt_status.mt_type = MT_ISONSTREAM_SC; - mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT; - mt_status.mt_dsreg = - ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | - ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); - mt_status.mt_blkno = STps->drv_block; - mt_status.mt_fileno = STps->drv_file; - if (STp->block_size != 0) { - if (STps->rw == ST_WRITING) - mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; - else if (STps->rw == ST_READING) - mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes + - STp->block_size - 1) / STp->block_size; - } - - mt_status.mt_gstat = 0; - if (STp->drv_write_prot) - mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); - if (mt_status.mt_blkno == 0) { - if (mt_status.mt_fileno == 0) - mt_status.mt_gstat |= GMT_BOT(0xffffffff); - else - mt_status.mt_gstat |= GMT_EOF(0xffffffff); - } - mt_status.mt_resid = STp->partition; - if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) - mt_status.mt_gstat |= GMT_EOT(0xffffffff); - else if (STps->eof >= ST_EOM_OK) - mt_status.mt_gstat |= GMT_EOD(0xffffffff); - if (STp->density == 1) - mt_status.mt_gstat |= GMT_D_800(0xffffffff); - else if (STp->density == 2) - mt_status.mt_gstat |= GMT_D_1600(0xffffffff); - else if (STp->density == 3) - mt_status.mt_gstat |= GMT_D_6250(0xffffffff); - if (STp->ready == ST_READY) - mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); - if (STp->ready == ST_NO_TAPE) - mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); - if (STps->at_sm) - mt_status.mt_gstat |= GMT_SM(0xffffffff); - if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || - STp->drv_buffer != 0) - mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); - - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); - if (i) { - retval = (-EFAULT); - goto out; - } - - STp->recover_erreg = 0; /* Clear after read */ - retval = 0; - goto out; - } /* End of MTIOCGET */ - - if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { - struct mtpos mt_pos; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { - retval = (-EINVAL); - goto out; - } - if (STp->raw) - blk = osst_get_frame_position(STp, &SRpnt); - else - blk = osst_get_sector(STp, &SRpnt); - if (blk < 0) { - retval = blk; - goto out; - } - mt_pos.mt_blkno = blk; - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); - if (i) - retval = -EFAULT; - goto out; - } - if (SRpnt) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - retval = scsi_ioctl(STp->device, cmd_in, p); - mutex_unlock(&osst_int_mutex); - return retval; - -out: - if (SRpnt) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - mutex_unlock(&osst_int_mutex); - - return retval; -} - -#ifdef CONFIG_COMPAT -static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg) -{ - struct osst_tape *STp = file->private_data; - struct scsi_device *sdev = STp->device; - int ret = -ENOIOCTLCMD; - if (sdev->host->hostt->compat_ioctl) { - - ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); - - } - return ret; -} -#endif - - - -/* Memory handling routines */ - -/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ -static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) -{ - int i; - gfp_t priority; - struct osst_buffer *tb; - - if (from_initialization) - priority = GFP_ATOMIC; - else - priority = GFP_KERNEL; - - i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = kzalloc(i, priority); - if (!tb) { - printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); - return NULL; - } - - tb->sg_segs = tb->orig_sg_segs = 0; - tb->use_sg = max_sg; - tb->in_use = 1; - tb->dma = need_dma; - tb->buffer_size = 0; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG - "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n", - i, max_sg, need_dma); -#endif - return tb; -} - -/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ -static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) -{ - int segs, nbr, max_segs, b_size, order, got; - gfp_t priority; - - if (STbuffer->buffer_size >= OS_FRAME_SIZE) - return 1; - - if (STbuffer->sg_segs) { - printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n"); - normalize_buffer(STbuffer); - } - /* See how many segments we can use -- need at least two */ - nbr = max_segs = STbuffer->use_sg; - if (nbr <= 2) - return 0; - - priority = GFP_KERNEL /* | __GFP_NOWARN */; - if (need_dma) - priority |= GFP_DMA; - - /* Try to allocate the first segment up to OS_DATA_SIZE and the others - big enough to reach the goal (code assumes no segments in place) */ - for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) { - struct page *page = alloc_pages(priority, order); - - STbuffer->sg[0].offset = 0; - if (page != NULL) { - sg_set_page(&STbuffer->sg[0], page, b_size, 0); - STbuffer->b_data = page_address(page); - break; - } - } - if (sg_page(&STbuffer->sg[0]) == NULL) { - printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n"); - return 0; - } - /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */ - for (segs=STbuffer->sg_segs=1, got=b_size; - segs < max_segs && got < OS_FRAME_SIZE; ) { - struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); - STbuffer->sg[segs].offset = 0; - if (page == NULL) { - printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", - OS_FRAME_SIZE); -#if DEBUG - STbuffer->buffer_size = got; -#endif - normalize_buffer(STbuffer); - return 0; - } - sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0); - got += STbuffer->sg[segs].length; - STbuffer->buffer_size = got; - STbuffer->sg_segs = ++segs; - } -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG - "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n", - got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data); - printk(OSST_DEB_MSG - "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n", - STbuffer->sg[0].length, page_address(STbuffer->sg[0].page), - STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page)); - } -#endif - - return 1; -} - - -/* Release the segments */ -static void normalize_buffer(struct osst_buffer *STbuffer) -{ - int i, order, b_size; - - for (i=0; i < STbuffer->sg_segs; i++) { - - for (b_size = PAGE_SIZE, order = 0; - b_size < STbuffer->sg[i].length; - b_size *= 2, order++); - - __free_pages(sg_page(&STbuffer->sg[i]), order); - STbuffer->buffer_size -= STbuffer->sg[i].length; - } -#if DEBUG - if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) - printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n", - STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); -#endif - STbuffer->sg_segs = STbuffer->orig_sg_segs = 0; -} - - -/* Move data from the user buffer to the tape buffer. Returns zero (success) or - negative error code. */ -static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count) -{ - int i, cnt, res, offset; - - for (i=0, offset=st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n", - do_count); - return (-EIO); - } - return 0; -} - - -/* Move data from the tape buffer to the user buffer. Returns zero (success) or - negative error code. */ -static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count) -{ - int i, cnt, res, offset; - - for (i=0, offset=st_bp->read_pointer; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes -= cnt; - st_bp->read_pointer += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count); - return (-EIO); - } - return 0; -} - -/* Sets the tail of the buffer after fill point to zero. - Returns zero (success) or negative error code. */ -static int osst_zero_buffer_tail(struct osst_buffer *st_bp) -{ - int i, offset, do_count, cnt; - - for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n"); - return (-EIO); - } - for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes; - i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count ; - memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt); - do_count -= cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count); - return (-EIO); - } - return 0; -} - -/* Copy a osst 32K chunk of memory into the buffer. - Returns zero (success) or negative error code. */ -static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr) -{ - int i, cnt, do_count = OS_DATA_SIZE; - - for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length < do_count ? - st_bp->sg[i].length : do_count ; - memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt); - do_count -= cnt; - ptr += cnt; - } - if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n", - do_count, i); - return (-EIO); - } - return 0; -} - -/* Copy a osst 32K chunk of memory from the buffer. - Returns zero (success) or negative error code. */ -static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr) -{ - int i, cnt, do_count = OS_DATA_SIZE; - - for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length < do_count ? - st_bp->sg[i].length : do_count ; - memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt); - do_count -= cnt; - ptr += cnt; - } - if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n", - do_count, i); - return (-EIO); - } - return 0; -} - - -/* Module housekeeping */ - -static void validate_options (void) -{ - if (max_dev > 0) - osst_max_dev = max_dev; - if (write_threshold_kbs > 0) - osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; - if (osst_write_threshold > osst_buffer_size) - osst_write_threshold = osst_buffer_size; - if (max_sg_segs >= OSST_FIRST_SG) - osst_max_sg_segs = max_sg_segs; -#if DEBUG - printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n", - osst_max_dev, osst_write_threshold, osst_max_sg_segs); -#endif -} - -#ifndef MODULE -/* Set the boot options. Syntax: osst=xxx,yyy,... - where xxx is write threshold in 1024 byte blocks, - and yyy is number of s/g segments to use. */ -static int __init osst_setup (char *str) -{ - int i, ints[5]; - char *stp; - - stp = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) - *parms[i].val = ints[i + 1]; - } else { - while (stp != NULL) { - for (i = 0; i < ARRAY_SIZE(parms); i++) { - int len = strlen(parms[i].name); - if (!strncmp(stp, parms[i].name, len) && - (*(stp + len) == ':' || *(stp + len) == '=')) { - *parms[i].val = - simple_strtoul(stp + len + 1, NULL, 0); - break; - } - } - if (i >= ARRAY_SIZE(parms)) - printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n", - stp); - stp = strchr(stp, ','); - if (stp) - stp++; - } - } - - return 1; -} - -__setup("osst=", osst_setup); - -#endif - -static const struct file_operations osst_fops = { - .owner = THIS_MODULE, - .read = osst_read, - .write = osst_write, - .unlocked_ioctl = osst_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = osst_compat_ioctl, -#endif - .open = os_scsi_tape_open, - .flush = os_scsi_tape_flush, - .release = os_scsi_tape_close, - .llseek = noop_llseek, -}; - -static int osst_supports(struct scsi_device * SDp) -{ - struct osst_support_data { - char *vendor; - char *model; - char *rev; - char *driver_hint; /* Name of the correct driver, NULL if unknown */ - }; - -static struct osst_support_data support_list[] = { - /* {"XXX", "Yy-", "", NULL}, example */ - SIGS_FROM_OSST, - {NULL, }}; - - struct osst_support_data *rp; - - /* We are willing to drive OnStream SC-x0 as well as the - * * IDE, ParPort, FireWire, USB variants, if accessible by - * * emulation layer (ide-scsi, usb-storage, ...) */ - - for (rp=&(support_list[0]); rp->vendor != NULL; rp++) - if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && - !strncmp(rp->model, SDp->model, strlen(rp->model)) && - !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) - return 1; - return 0; -} - -/* - * sysfs support for osst driver parameter information - */ - -static ssize_t version_show(struct device_driver *ddd, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", osst_version); -} - -static DRIVER_ATTR_RO(version); - -static int osst_create_sysfs_files(struct device_driver *sysfs) -{ - return driver_create_file(sysfs, &driver_attr_version); -} - -static void osst_remove_sysfs_files(struct device_driver *sysfs) -{ - driver_remove_file(sysfs, &driver_attr_version); -} - -/* - * sysfs support for accessing ADR header information - */ - -static ssize_t osst_adr_rev_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev); - return l; -} - -DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL); - -static ssize_t osst_linux_media_version_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version); - return l; -} - -DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL); - -static ssize_t osst_capacity_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity); - return l; -} - -DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL); - -static ssize_t osst_first_data_ppos_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos); - return l; -} - -DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL); - -static ssize_t osst_eod_frame_ppos_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos); - return l; -} - -DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL); - -static ssize_t osst_filemark_cnt_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt); - return l; -} - -DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); - -static struct class *osst_sysfs_class; - -static int osst_sysfs_init(void) -{ - osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); - if (IS_ERR(osst_sysfs_class)) { - printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); - return PTR_ERR(osst_sysfs_class); - } - - return 0; -} - -static void osst_sysfs_destroy(dev_t dev) -{ - device_destroy(osst_sysfs_class, dev); -} - -static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) -{ - struct device *osst_member; - int err; - - osst_member = device_create(osst_sysfs_class, device, dev, STp, - "%s", name); - if (IS_ERR(osst_member)) { - printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); - return PTR_ERR(osst_member); - } - - err = device_create_file(osst_member, &dev_attr_ADR_rev); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_media_version); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_capacity); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_BOT_frame); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_EOD_frame); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_file_count); - if (err) - goto err_out; - - return 0; - -err_out: - osst_sysfs_destroy(dev); - return err; -} - -static void osst_sysfs_cleanup(void) -{ - class_destroy(osst_sysfs_class); -} - -/* - * osst startup / cleanup code - */ - -static int osst_probe(struct device *dev) -{ - struct scsi_device * SDp = to_scsi_device(dev); - struct osst_tape * tpnt; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_buffer * buffer; - struct gendisk * drive; - int i, dev_num, err = -ENODEV; - - if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) - return -ENODEV; - - drive = alloc_disk(1); - if (!drive) { - printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n"); - return -ENODEV; - } - - /* if this is the first attach, build the infrastructure */ - write_lock(&os_scsi_tapes_lock); - if (os_scsi_tapes == NULL) { - os_scsi_tapes = kmalloc_array(osst_max_dev, - sizeof(struct osst_tape *), - GFP_ATOMIC); - if (os_scsi_tapes == NULL) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n"); - goto out_put_disk; - } - for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL; - } - - if (osst_nr_dev >= osst_max_dev) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev); - goto out_put_disk; - } - - /* find a free minor number */ - for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++) - ; - if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)"); - dev_num = i; - - /* allocate a struct osst_tape for this device */ - tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC); - if (!tpnt) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n"); - goto out_put_disk; - } - - /* allocate a buffer for this device */ - i = SDp->host->sg_tablesize; - if (osst_max_sg_segs < i) - i = osst_max_sg_segs; - buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i); - if (buffer == NULL) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n"); - kfree(tpnt); - goto out_put_disk; - } - os_scsi_tapes[dev_num] = tpnt; - tpnt->buffer = buffer; - tpnt->device = SDp; - drive->private_data = &tpnt->driver; - sprintf(drive->disk_name, "osst%d", dev_num); - tpnt->driver = &osst_template; - tpnt->drive = drive; - tpnt->in_use = 0; - tpnt->capacity = 0xfffff; - tpnt->dirty = 0; - tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ - tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; - tpnt->density = 0; - tpnt->do_auto_lock = OSST_AUTO_LOCK; - tpnt->can_bsr = OSST_IN_FILE_POS; - tpnt->can_partitions = 0; - tpnt->two_fm = OSST_TWO_FM; - tpnt->fast_mteom = OSST_FAST_MTEOM; - tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */ - tpnt->write_threshold = osst_write_threshold; - tpnt->default_drvbuffer = 0xff; /* No forced buffering */ - tpnt->partition = 0; - tpnt->new_partition = 0; - tpnt->nbr_partitions = 0; - tpnt->min_block = 512; - tpnt->max_block = OS_DATA_SIZE; - tpnt->timeout = OSST_TIMEOUT; - tpnt->long_timeout = OSST_LONG_TIMEOUT; - - /* Recognize OnStream tapes */ - /* We don't need to test for OnStream, as this has been done in detect () */ - tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev); - tpnt->omit_blklims = 1; - - tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || - (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp); - tpnt->frame_in_buffer = 0; - tpnt->header_ok = 0; - tpnt->linux_media = 0; - tpnt->header_cache = NULL; - - for (i=0; i < ST_NBR_MODES; i++) { - STm = &(tpnt->modes[i]); - STm->defined = 0; - STm->sysv = OSST_SYSV; - STm->defaults_for_writes = 0; - STm->do_async_writes = OSST_ASYNC_WRITES; - STm->do_buffer_writes = OSST_BUFFER_WRITES; - STm->do_read_ahead = OSST_READ_AHEAD; - STm->default_compression = ST_DONT_TOUCH; - STm->default_blksize = 512; - STm->default_density = (-1); /* No forced density */ - } - - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(tpnt->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = (-1); - STps->drv_file = (-1); - } - - tpnt->current_mode = 0; - tpnt->modes[0].defined = 1; - tpnt->modes[2].defined = 1; - tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0; - - mutex_init(&tpnt->lock); - osst_nr_dev++; - write_unlock(&os_scsi_tapes_lock); - - { - char name[8]; - - /* Rewind entry */ - err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); - if (err) - goto out_free_buffer; - - /* No-rewind entry */ - snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); - err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); - if (err) - goto out_free_sysfs1; - } - - sdev_printk(KERN_INFO, SDp, - "osst :I: Attached OnStream %.5s tape as %s\n", - SDp->model, tape_name(tpnt)); - - return 0; - -out_free_sysfs1: - osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); -out_free_buffer: - kfree(buffer); -out_put_disk: - put_disk(drive); - return err; -}; - -static int osst_remove(struct device *dev) -{ - struct scsi_device * SDp = to_scsi_device(dev); - struct osst_tape * tpnt; - int i; - - if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) - return 0; - - write_lock(&os_scsi_tapes_lock); - for(i=0; i < osst_max_dev; i++) { - if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) { - osst_sysfs_destroy(MKDEV(OSST_MAJOR, i)); - osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128)); - tpnt->device = NULL; - put_disk(tpnt->drive); - os_scsi_tapes[i] = NULL; - osst_nr_dev--; - write_unlock(&os_scsi_tapes_lock); - vfree(tpnt->header_cache); - if (tpnt->buffer) { - normalize_buffer(tpnt->buffer); - kfree(tpnt->buffer); - } - kfree(tpnt); - return 0; - } - } - write_unlock(&os_scsi_tapes_lock); - return 0; -} - -static int __init init_osst(void) -{ - int err; - - printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); - - validate_options(); - - err = osst_sysfs_init(); - if (err) - return err; - - err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); - if (err < 0) { - printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); - goto err_out; - } - - err = scsi_register_driver(&osst_template.gendrv); - if (err) - goto err_out_chrdev; - - err = osst_create_sysfs_files(&osst_template.gendrv); - if (err) - goto err_out_scsidrv; - - return 0; - -err_out_scsidrv: - scsi_unregister_driver(&osst_template.gendrv); -err_out_chrdev: - unregister_chrdev(OSST_MAJOR, "osst"); -err_out: - osst_sysfs_cleanup(); - return err; -} - -static void __exit exit_osst (void) -{ - int i; - struct osst_tape * STp; - - osst_remove_sysfs_files(&osst_template.gendrv); - scsi_unregister_driver(&osst_template.gendrv); - unregister_chrdev(OSST_MAJOR, "osst"); - osst_sysfs_cleanup(); - - if (os_scsi_tapes) { - for (i=0; i < osst_max_dev; ++i) { - if (!(STp = os_scsi_tapes[i])) continue; - /* This is defensive, supposed to happen during detach */ - vfree(STp->header_cache); - if (STp->buffer) { - normalize_buffer(STp->buffer); - kfree(STp->buffer); - } - put_disk(STp->drive); - kfree(STp); - } - kfree(os_scsi_tapes); - } - printk(KERN_INFO "osst :I: Unloaded.\n"); -} - -module_init(init_osst); -module_exit(exit_osst); diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h deleted file mode 100644 index b90ae280853d..000000000000 --- a/drivers/scsi/osst.h +++ /dev/null @@ -1,651 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $ - */ - -#include <asm/byteorder.h> -#include <linux/completion.h> -#include <linux/mutex.h> - -/* FIXME - rename and use the following two types or delete them! - * and the types really should go to st.h anyway... - * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) - */ -typedef struct { - unsigned device_type :5; /* Peripheral Device Type */ - unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ - unsigned reserved1_6t0 :7; /* Reserved */ - unsigned rmb :1; /* Removable Medium Bit */ - unsigned ansi_version :3; /* ANSI Version */ - unsigned ecma_version :3; /* ECMA Version */ - unsigned iso_version :2; /* ISO Version */ - unsigned response_format :4; /* Response Data Format */ - unsigned reserved3_45 :2; /* Reserved */ - unsigned reserved3_6 :1; /* TrmIOP - Reserved */ - unsigned reserved3_7 :1; /* AENC - Reserved */ - u8 additional_length; /* Additional Length (total_length-4) */ - u8 rsv5, rsv6, rsv7; /* Reserved */ - u8 vendor_id[8]; /* Vendor Identification */ - u8 product_id[16]; /* Product Identification */ - u8 revision_level[4]; /* Revision Level */ - u8 vendor_specific[20]; /* Vendor Specific - Optional */ - u8 reserved56t95[40]; /* Reserved - Optional */ - /* Additional information may be returned */ -} idetape_inquiry_result_t; - -/* - * READ POSITION packet command - Data Format (From Table 6-57) - */ -typedef struct { - unsigned reserved0_10 :2; /* Reserved */ - unsigned bpu :1; /* Block Position Unknown */ - unsigned reserved0_543 :3; /* Reserved */ - unsigned eop :1; /* End Of Partition */ - unsigned bop :1; /* Beginning Of Partition */ - u8 partition; /* Partition Number */ - u8 reserved2, reserved3; /* Reserved */ - u32 first_block; /* First Block Location */ - u32 last_block; /* Last Block Location (Optional) */ - u8 reserved12; /* Reserved */ - u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ - u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ -} idetape_read_position_result_t; - -/* - * Follows structures which are related to the SELECT SENSE / MODE SENSE - * packet commands. - */ -#define COMPRESSION_PAGE 0x0f -#define COMPRESSION_PAGE_LENGTH 16 - -#define CAPABILITIES_PAGE 0x2a -#define CAPABILITIES_PAGE_LENGTH 20 - -#define TAPE_PARAMTR_PAGE 0x2b -#define TAPE_PARAMTR_PAGE_LENGTH 16 - -#define NUMBER_RETRIES_PAGE 0x2f -#define NUMBER_RETRIES_PAGE_LENGTH 4 - -#define BLOCK_SIZE_PAGE 0x30 -#define BLOCK_SIZE_PAGE_LENGTH 4 - -#define BUFFER_FILLING_PAGE 0x33 -#define BUFFER_FILLING_PAGE_LENGTH 4 - -#define VENDOR_IDENT_PAGE 0x36 -#define VENDOR_IDENT_PAGE_LENGTH 8 - -#define LOCATE_STATUS_PAGE 0x37 -#define LOCATE_STATUS_PAGE_LENGTH 0 - -#define MODE_HEADER_LENGTH 4 - - -/* - * REQUEST SENSE packet command result - Data Format. - */ -typedef struct { - unsigned error_code :7; /* Current of deferred errors */ - unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ - unsigned sense_key :4; /* Sense Key */ - unsigned reserved2_4 :1; /* Reserved */ - unsigned ili :1; /* Incorrect Length Indicator */ - unsigned eom :1; /* End Of Medium */ - unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ - unsigned sk_specific1 :7; /* Sense Key Specific */ - unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ -} idetape_request_sense_result_t; - -/* - * Mode Parameter Header for the MODE SENSE packet command - */ -typedef struct { - u8 mode_data_length; /* Length of the following data transfer */ - u8 medium_type; /* Medium Type */ - u8 dsp; /* Device Specific Parameter */ - u8 bdl; /* Block Descriptor Length */ -} osst_mode_parameter_header_t; - -/* - * Mode Parameter Block Descriptor the MODE SENSE packet command - * - * Support for block descriptors is optional. - */ -typedef struct { - u8 density_code; /* Medium density code */ - u8 blocks[3]; /* Number of blocks */ - u8 reserved4; /* Reserved */ - u8 length[3]; /* Block Length */ -} osst_parameter_block_descriptor_t; - -/* - * The Data Compression Page, as returned by the MODE SENSE packet command. - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved0 :1; /* Reserved */ - unsigned page_code :6; /* Page Code - Should be 0xf */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page Code - Should be 0xf */ - unsigned reserved0 :1; /* Reserved */ - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 14 */ -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned dce :1; /* Data Compression Enable */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned reserved2 :6; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved2 :6; /* Reserved */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned dce :1; /* Data Compression Enable */ -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned dde :1; /* Data Decompression Enable */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned reserved3 :5; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved3 :5; /* Reserved */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned dde :1; /* Data Decompression Enable */ -#else -#error "Please fix <asm/byteorder.h>" -#endif - u32 ca; /* Compression Algorithm */ - u32 da; /* Decompression Algorithm */ - u8 reserved[4]; /* Reserved */ -} osst_data_compression_page_t; - -/* - * The Medium Partition Page, as returned by the MODE SENSE packet command. - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; /* Reserved */ - unsigned page_code :6; /* Page Code - Should be 0x11 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page Code - Should be 0x11 */ - unsigned reserved1_6 :1; /* Reserved */ - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 6 */ - u8 map; /* Maximum Additional Partitions - Should be 0 */ - u8 apd; /* Additional Partitions Defined - Should be 0 */ -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned fdp :1; /* Fixed Data Partitions */ - unsigned sdp :1; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned psum :2; /* Should be 0 */ - unsigned reserved4_012 :3; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved4_012 :3; /* Reserved */ - unsigned psum :2; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned sdp :1; /* Should be 0 */ - unsigned fdp :1; /* Fixed Data Partitions */ -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 mfr; /* Medium Format Recognition */ - u8 reserved[2]; /* Reserved */ -} osst_medium_partition_page_t; - -/* - * Capabilities and Mechanical Status Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved1_67 :2; - unsigned page_code :6; /* Page code - Should be 0x2a */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x2a */ - unsigned reserved1_67 :2; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 0x12 */ - u8 reserved2, reserved3; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved4_67 :2; - unsigned sprev :1; /* Supports SPACE in the reverse direction */ - unsigned reserved4_1234 :4; - unsigned ro :1; /* Read Only Mode */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned ro :1; /* Read Only Mode */ - unsigned reserved4_1234 :4; - unsigned sprev :1; /* Supports SPACE in the reverse direction */ - unsigned reserved4_67 :2; -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved5_67 :2; - unsigned qfa :1; /* Supports the QFA two partition formats */ - unsigned reserved5_4 :1; - unsigned efmt :1; /* Supports ERASE command initiated formatting */ - unsigned reserved5_012 :3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved5_012 :3; - unsigned efmt :1; /* Supports ERASE command initiated formatting */ - unsigned reserved5_4 :1; - unsigned qfa :1; /* Supports the QFA two partition formats */ - unsigned reserved5_67 :2; -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned cmprs :1; /* Supports data compression */ - unsigned ecc :1; /* Supports error correction */ - unsigned reserved6_45 :2; /* Reserved */ - unsigned eject :1; /* The device can eject the volume */ - unsigned prevent :1; /* The device defaults in the prevent state after power up */ - unsigned locked :1; /* The volume is locked */ - unsigned lock :1; /* Supports locking the volume */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned lock :1; /* Supports locking the volume */ - unsigned locked :1; /* The volume is locked */ - unsigned prevent :1; /* The device defaults in the prevent state after power up */ - unsigned eject :1; /* The device can eject the volume */ - unsigned reserved6_45 :2; /* Reserved */ - unsigned ecc :1; /* Supports error correction */ - unsigned cmprs :1; /* Supports data compression */ -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ - /* transfers for slow buffer memory ??? */ - /* Also 32768 block size in some cases */ - unsigned reserved7_3_6 :4; - unsigned blk1024 :1; /* Supports 1024 bytes block size */ - unsigned blk512 :1; /* Supports 512 bytes block size */ - unsigned reserved7_0 :1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved7_0 :1; - unsigned blk512 :1; /* Supports 512 bytes block size */ - unsigned blk1024 :1; /* Supports 1024 bytes block size */ - unsigned reserved7_3_6 :4; - unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ - /* transfers for slow buffer memory ??? */ - /* Also 32768 block size in some cases */ -#else -#error "Please fix <asm/byteorder.h>" -#endif - __be16 max_speed; /* Maximum speed supported in KBps */ - u8 reserved10, reserved11; - __be16 ctl; /* Continuous Transfer Limit in blocks */ - __be16 speed; /* Current Speed, in KBps */ - __be16 buffer_size; /* Buffer Size, in 512 bytes */ - u8 reserved18, reserved19; -} osst_capabilities_page_t; - -/* - * Block Size Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; - unsigned page_code :6; /* Page code - Should be 0x30 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x30 */ - unsigned reserved1_6 :1; - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 2 */ - u8 reserved2; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned one :1; - unsigned reserved2_6 :1; - unsigned record32_5 :1; - unsigned record32 :1; - unsigned reserved2_23 :2; - unsigned play32_5 :1; - unsigned play32 :1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned play32 :1; - unsigned play32_5 :1; - unsigned reserved2_23 :2; - unsigned record32 :1; - unsigned record32_5 :1; - unsigned reserved2_6 :1; - unsigned one :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif -} osst_block_size_page_t; - -/* - * Tape Parameters Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; - unsigned page_code :6; /* Page code - Should be 0x2b */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x2b */ - unsigned reserved1_6 :1; - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 reserved2; - u8 density; - u8 reserved3,reserved4; - __be16 segtrk; - __be16 trks; - u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; -} osst_tape_paramtr_page_t; - -/* OnStream definitions */ - -#define OS_CONFIG_PARTITION (0xff) -#define OS_DATA_PARTITION (0) -#define OS_PARTITION_VERSION (1) - -/* - * partition - */ -typedef struct os_partition_s { - __u8 partition_num; - __u8 par_desc_ver; - __be16 wrt_pass_cntr; - __be32 first_frame_ppos; - __be32 last_frame_ppos; - __be32 eod_frame_ppos; -} os_partition_t; - -/* - * DAT entry - */ -typedef struct os_dat_entry_s { - __be32 blk_sz; - __be16 blk_cnt; - __u8 flags; - __u8 reserved; -} os_dat_entry_t; - -/* - * DAT - */ -#define OS_DAT_FLAGS_DATA (0xc) -#define OS_DAT_FLAGS_MARK (0x1) - -typedef struct os_dat_s { - __u8 dat_sz; - __u8 reserved1; - __u8 entry_cnt; - __u8 reserved3; - os_dat_entry_t dat_list[16]; -} os_dat_t; - -/* - * Frame types - */ -#define OS_FRAME_TYPE_FILL (0) -#define OS_FRAME_TYPE_EOD (1 << 0) -#define OS_FRAME_TYPE_MARKER (1 << 1) -#define OS_FRAME_TYPE_HEADER (1 << 3) -#define OS_FRAME_TYPE_DATA (1 << 7) - -/* - * AUX - */ -typedef struct os_aux_s { - __be32 format_id; /* hardware compatibility AUX is based on */ - char application_sig[4]; /* driver used to write this media */ - __be32 hdwr; /* reserved */ - __be32 update_frame_cntr; /* for configuration frame */ - __u8 frame_type; - __u8 frame_type_reserved; - __u8 reserved_18_19[2]; - os_partition_t partition; - __u8 reserved_36_43[8]; - __be32 frame_seq_num; - __be32 logical_blk_num_high; - __be32 logical_blk_num; - os_dat_t dat; - __u8 reserved188_191[4]; - __be32 filemark_cnt; - __be32 phys_fm; - __be32 last_mark_ppos; - __u8 reserved204_223[20]; - - /* - * __u8 app_specific[32]; - * - * Linux specific fields: - */ - __be32 next_mark_ppos; /* when known, points to next marker */ - __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ - __u8 linux_specific[24]; - - __u8 reserved_256_511[256]; -} os_aux_t; - -#define OS_FM_TAB_MAX 1024 - -typedef struct os_fm_tab_s { - __u8 fm_part_num; - __u8 reserved_1; - __u8 fm_tab_ent_sz; - __u8 reserved_3; - __be16 fm_tab_ent_cnt; - __u8 reserved6_15[10]; - __be32 fm_tab_ent[OS_FM_TAB_MAX]; -} os_fm_tab_t; - -typedef struct os_ext_trk_ey_s { - __u8 et_part_num; - __u8 fmt; - __be16 fm_tab_off; - __u8 reserved4_7[4]; - __be32 last_hlb_hi; - __be32 last_hlb; - __be32 last_pp; - __u8 reserved20_31[12]; -} os_ext_trk_ey_t; - -typedef struct os_ext_trk_tb_s { - __u8 nr_stream_part; - __u8 reserved_1; - __u8 et_ent_sz; - __u8 reserved3_15[13]; - os_ext_trk_ey_t dat_ext_trk_ey; - os_ext_trk_ey_t qfa_ext_trk_ey; -} os_ext_trk_tb_t; - -typedef struct os_header_s { - char ident_str[8]; - __u8 major_rev; - __u8 minor_rev; - __be16 ext_trk_tb_off; - __u8 reserved12_15[4]; - __u8 pt_par_num; - __u8 pt_reserved1_3[3]; - os_partition_t partition[16]; - __be32 cfg_col_width; - __be32 dat_col_width; - __be32 qfa_col_width; - __u8 cartridge[16]; - __u8 reserved304_511[208]; - __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ - os_ext_trk_tb_t ext_track_tb; - __u8 reserved17272_17735[464]; - os_fm_tab_t dat_fm_tab; - os_fm_tab_t qfa_fm_tab; - __u8 reserved25960_32767[6808]; -} os_header_t; - - -/* - * OnStream ADRL frame - */ -#define OS_FRAME_SIZE (32 * 1024 + 512) -#define OS_DATA_SIZE (32 * 1024) -#define OS_AUX_SIZE (512) -//#define OSST_MAX_SG 2 - -/* The OnStream tape buffer descriptor. */ -struct osst_buffer { - unsigned char in_use; - unsigned char dma; /* DMA-able buffer */ - int buffer_size; - int buffer_blocks; - int buffer_bytes; - int read_pointer; - int writing; - int midlevel_result; - int syscall_result; - struct osst_request *last_SRpnt; - struct st_cmdstatus cmdstat; - struct rq_map_data map_data; - unsigned char *b_data; - os_aux_t *aux; /* onstream AUX structure at end of each block */ - unsigned short use_sg; /* zero or number of s/g segments for this adapter */ - unsigned short sg_segs; /* number of segments in s/g list */ - unsigned short orig_sg_segs; /* number of segments allocated at first try */ - struct scatterlist sg[1]; /* MUST BE last item */ -} ; - -/* The OnStream tape drive descriptor */ -struct osst_tape { - struct scsi_driver *driver; - unsigned capacity; - struct scsi_device *device; - struct mutex lock; /* for serialization */ - struct completion wait; /* for SCSI commands */ - struct osst_buffer * buffer; - - /* Drive characteristics */ - unsigned char omit_blklims; - unsigned char do_auto_lock; - unsigned char can_bsr; - unsigned char can_partitions; - unsigned char two_fm; - unsigned char fast_mteom; - unsigned char restr_dma; - unsigned char scsi2_logical; - unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ - unsigned char pos_unknown; /* after reset position unknown */ - int write_threshold; - int timeout; /* timeout for normal commands */ - int long_timeout; /* timeout for commands known to take long time*/ - - /* Mode characteristics */ - struct st_modedef modes[ST_NBR_MODES]; - int current_mode; - - /* Status variables */ - int partition; - int new_partition; - int nbr_partitions; /* zero until partition support enabled */ - struct st_partstat ps[ST_NBR_PARTITIONS]; - unsigned char dirty; - unsigned char ready; - unsigned char write_prot; - unsigned char drv_write_prot; - unsigned char in_use; - unsigned char blksize_changed; - unsigned char density_changed; - unsigned char compression_changed; - unsigned char drv_buffer; - unsigned char density; - unsigned char door_locked; - unsigned char rew_at_close; - unsigned char inited; - int block_size; - int min_block; - int max_block; - int recover_count; /* from tape opening */ - int abort_count; - int write_count; - int read_count; - int recover_erreg; /* from last status call */ - /* - * OnStream specific data - */ - int os_fw_rev; /* the firmware revision * 10000 */ - unsigned char raw; /* flag OnStream raw access (32.5KB block size) */ - unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */ - unsigned char frame_in_buffer; /* flag that the frame as per frame_seq_number - * has been read into STp->buffer and is valid */ - int frame_seq_number; /* logical frame number */ - int logical_blk_num; /* logical block number */ - unsigned first_frame_position; /* physical frame to be transferred to/from host */ - unsigned last_frame_position; /* physical frame to be transferd to/from tape */ - int cur_frames; /* current number of frames in internal buffer */ - int max_frames; /* max number of frames in internal buffer */ - char application_sig[5]; /* application signature */ - unsigned char fast_open; /* flag that reminds us we didn't check headers at open */ - unsigned short wrt_pass_cntr; /* write pass counter */ - int update_frame_cntr; /* update frame counter */ - int onstream_write_error; /* write error recovery active */ - int header_ok; /* header frame verified ok */ - int linux_media; /* reading linux-specifc media */ - int linux_media_version; - os_header_t * header_cache; /* cache is kept for filemark positions */ - int filemark_cnt; - int first_mark_ppos; - int last_mark_ppos; - int last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ - int first_data_ppos; - int eod_frame_ppos; - int eod_frame_lfa; - int write_type; /* used in write error recovery */ - int read_error_frame; /* used in read error recovery */ - unsigned long cmd_start_time; - unsigned long max_cmd_time; - -#if DEBUG - unsigned char write_pending; - int nbr_finished; - int nbr_waits; - unsigned char last_cmnd[6]; - unsigned char last_sense[16]; -#endif - struct gendisk *drive; -} ; - -/* scsi tape command */ -struct osst_request { - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int result; - struct osst_tape *stp; - struct completion *waiting; - struct bio *bio; -}; - -/* Values of write_type */ -#define OS_WRITE_DATA 0 -#define OS_WRITE_EOD 1 -#define OS_WRITE_NEW_MARK 2 -#define OS_WRITE_LAST_MARK 3 -#define OS_WRITE_HEADER 4 -#define OS_WRITE_FILLER 5 - -/* Additional rw state */ -#define OS_WRITING_COMPLETE 3 diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h deleted file mode 100644 index 83c1d4fb11db..000000000000 --- a/drivers/scsi/osst_detect.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define SIGS_FROM_OSST \ - {"OnStream", "SC-", "", "osst"}, \ - {"OnStream", "DI-", "", "osst"}, \ - {"OnStream", "DP-", "", "osst"}, \ - {"OnStream", "FW-", "", "osst"}, \ - {"OnStream", "USB", "", "osst"} diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h deleted file mode 100644 index a6a389b88876..000000000000 --- a/drivers/scsi/osst_options.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - The compile-time configurable defaults for the Linux SCSI tape driver. - - Copyright 1995 Kai Makisara. - - Last modified: Wed Sep 2 21:24:07 1998 by root@home - - Changed (and renamed) for OnStream SCSI drives garloff@suse.de - 2000-06-21 - - $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $ -*/ - -#ifndef _OSST_OPTIONS_H -#define _OSST_OPTIONS_H - -/* The minimum limit for the number of SCSI tape devices is determined by - OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by - OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */ -#define OSST_MAX_TAPES 4 - -/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the - record been read by the user program even if the tape has moved further - because of buffered reads. Should be set to zero to support also drives - that can't space backwards over records. NOTE: The tape will be - spaced backwards over an "accidentally" crossed filemark in any case. */ -#define OSST_IN_FILE_POS 1 - -/* The tape driver buffer size in kilobytes. */ -/* Don't change, as this is the HW blocksize */ -#define OSST_BUFFER_BLOCKS 32 - -/* The number of kilobytes of data in the buffer that triggers an - asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES - below. */ -#define OSST_WRITE_THRESHOLD_BLOCKS 32 - -/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for - * * write error recovery when writing near end of medium. ENOSPC is returned - * * when write() is called and the tape write position is within this number - * * of blocks from the tape capacity. */ -#define OSST_EOM_RESERVE 300 - -/* The maximum number of tape buffers the driver allocates. The number - is also constrained by the number of drives detected. Determines the - maximum number of concurrently active tape drives. */ -#define OSST_MAX_BUFFERS OSST_MAX_TAPES - -/* Maximum number of scatter/gather segments */ -/* Fit one buffer in pages and add one for the AUX header */ -#define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1) - -/* The number of scatter/gather segments to allocate at first try (must be - smaller or equal to the maximum). */ -#define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) - -/* The size of the first scatter/gather segments (determines the maximum block - size for SCSI adapters not supporting scatter/gather). The default is set - to try to allocate the buffer as one chunk. */ -#define OSST_FIRST_ORDER (15-PAGE_SHIFT) - - -/* The following lines define defaults for properties that can be set - separately for each drive using the MTSTOPTIONS ioctl. */ - -/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a - file being written. Some drives can't handle two filemarks at the - end of data. */ -#define OSST_TWO_FM 0 - -/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are - buffered until the driver buffer is full or asynchronous write is - triggered. */ -#define OSST_BUFFER_WRITES 1 - -/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started - without waiting for it to finish. May cause problems in multiple - tape backups. */ -#define OSST_ASYNC_WRITES 1 - -/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block - mode. */ -#define OSST_READ_AHEAD 1 - -/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first - read or write command after the device is opened. The door is opened - when the device is closed. */ -#define OSST_AUTO_LOCK 0 - -/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the - direct SCSI command. The file number status is lost but this method - is fast with some drives. Otherwise MTEOM is done by spacing over - files and the file number status is retained. */ -#define OSST_FAST_MTEOM 0 - -/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for - MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL - is zero. */ -#define OSST_SCSI2LOGICAL 0 - -/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics. - The default is BSD semantics. */ -#define OSST_SYSV 0 - - -#endif diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index 2d435f105b16..2368f34efba3 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # PCMCIA SCSI adapter configuration # @@ -19,6 +20,16 @@ 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" + select SCSI_FDOMAIN + 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 a5a24dd44e7e..02f5b44a2685 100644 --- a/drivers/scsi/pcmcia/Makefile +++ b/drivers/scsi/pcmcia/Makefile @@ -4,6 +4,7 @@ ccflags-y := -I $(srctree)/drivers/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 diff --git a/drivers/scsi/pcmcia/fdomain_cs.c b/drivers/scsi/pcmcia/fdomain_cs.c new file mode 100644 index 000000000000..e42acf314d06 --- /dev/null +++ b/drivers/scsi/pcmcia/fdomain_cs.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) +/* + * Driver for Future Domain-compatible PCMCIA SCSI cards + * Copyright 2019 Ondrej Zary + * + * 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. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <scsi/scsi_host.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> +#include "fdomain.h" + +MODULE_AUTHOR("Ondrej Zary, David Hinds"); +MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data) +{ + p_dev->io_lines = 10; + p_dev->resource[0]->end = FDOMAIN_REGION_SIZE; + 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_probe(struct pcmcia_device *link) +{ + int ret; + struct Scsi_Host *sh; + + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + link->config_regs = PRESENT_OPTION; + + ret = pcmcia_loop_config(link, fdomain_config_check, NULL); + if (ret) + return ret; + + ret = pcmcia_enable_device(link); + if (ret) + goto fail_disable; + + if (!request_region(link->resource[0]->start, FDOMAIN_REGION_SIZE, + "fdomain_cs")) + goto fail_disable; + + sh = fdomain_create(link->resource[0]->start, link->irq, 7, &link->dev); + if (!sh) { + dev_err(&link->dev, "Controller initialization failed"); + ret = -ENODEV; + goto fail_release; + } + + link->priv = sh; + + return 0; + +fail_release: + release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE); +fail_disable: + pcmcia_disable_device(link); + return ret; +} + +static void fdomain_remove(struct pcmcia_device *link) +{ + fdomain_destroy(link->priv); + release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE); + pcmcia_disable_device(link); +} + +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_remove, + .id_table = fdomain_ids, +}; + +module_pcmcia_driver(fdomain_cs_driver); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index a81748e6e8fb..97416e1dcc5b 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -789,7 +789,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out); SCpnt->SCp.buffers_residual--; - SCpnt->SCp.buffer++; + SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer); SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; @@ -887,7 +887,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); SCpnt->SCp.buffers_residual--; - SCpnt->SCp.buffer++; + SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer); SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index d1e98a6ea28f..a366ff1a3959 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * sym53c500_cs.c Bob Tracy (rct@frus.com) * @@ -25,16 +26,6 @@ * Original by Tom Corner (tcorner@via.at) was adapted from a * driver for the Qlogic SCSI card written by * David Hinds (dhinds@allegro.stanford.edu). -* -* 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 SYM53C500_DEBUG 0 diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index d193961ea82f..6b85016b4db3 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -462,6 +462,24 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev, } static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL); /** + * event_log_size_show - event log size + * @cdev: pointer to embedded class device + * @buf: the buffer returned + * + * A sysfs read shost attribute. + */ +static ssize_t event_log_size_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + + return snprintf(buf, PAGE_SIZE, "%d\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size); +} +static DEVICE_ATTR_RO(event_log_size); +/** * pm8001_ctl_aap_log_show - IOP event log * @cdev: pointer to embedded class device * @buf: the buffer returned @@ -474,25 +492,26 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev, struct Scsi_Host *shost = class_to_shost(cdev); struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; -#define IOP_MEMMAP(r, c) \ - (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \ - + (c))) - int i; char *str = buf; - int max = 2; - for (i = 0; i < max; i++) { - str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" - "0x%08x 0x%08x\n", - IOP_MEMMAP(i, 0), - IOP_MEMMAP(i, 4), - IOP_MEMMAP(i, 8), - IOP_MEMMAP(i, 12), - IOP_MEMMAP(i, 16), - IOP_MEMMAP(i, 20), - IOP_MEMMAP(i, 24), - IOP_MEMMAP(i, 28)); + u32 read_size = + pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024; + static u32 start, end, count; + u32 max_read_times = 32; + u32 max_count = (read_size * 1024) / (max_read_times * 4); + u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr; + + if ((count % max_count) == 0) { + start = 0; + end = max_read_times; + count = 0; + } else { + start = end; + end = end + max_read_times; } + for (; start < end; start++) + str += sprintf(str, "%08x ", *(temp+start)); + count++; return str - buf; } static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); @@ -796,6 +815,7 @@ struct device_attribute *pm8001_host_attrs[] = { &dev_attr_max_sg_list, &dev_attr_sas_spec_support, &dev_attr_logging_level, + &dev_attr_event_log_size, &dev_attr_host_sas_address, &dev_attr_bios_version, &dev_attr_ib_log, diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index d0bb357034d8..68a8217032d0 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -960,9 +960,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) return -1; } regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GPIO Output Control Register:" - " = 0x%x\n", regVal)); + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("GPIO Output Control Register:" + " = 0x%x\n", regVal)); /* set GPIO-0 output control to tri-state */ regVal &= 0xFFFFFFFC; pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal); @@ -1204,6 +1204,7 @@ void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha) } } +#ifndef PM8001_USE_MSIX /** * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt * @pm8001_ha: our hba card information @@ -1225,6 +1226,8 @@ pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha) pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL); } +#else + /** * pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt * @pm8001_ha: our hba card information @@ -1256,6 +1259,7 @@ pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha, msi_index += MSIX_TABLE_BASE; pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_DISABLE); } +#endif /** * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt @@ -1266,10 +1270,9 @@ pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec) { #ifdef PM8001_USE_MSIX pm8001_chip_msix_interrupt_enable(pm8001_ha, 0); - return; -#endif +#else pm8001_chip_intx_interrupt_enable(pm8001_ha); - +#endif } /** @@ -1281,10 +1284,9 @@ pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) { #ifdef PM8001_USE_MSIX pm8001_chip_msix_interrupt_disable(pm8001_ha, 0); - return; -#endif +#else pm8001_chip_intx_interrupt_disable(pm8001_ha); - +#endif } /** @@ -2354,7 +2356,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { if (!((t->dev->parent) && - (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) { + (dev_is_expander(t->dev->parent->dev_type)))) { for (i = 0 , j = 4; j <= 7 && i <= 3; i++ , j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0 , j = 0; j <= 3 && i <= 3; i++ , j++) @@ -2898,7 +2900,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) static void mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) { - u32 param; struct sas_task *t; struct pm8001_ccb_info *ccb; unsigned long flags; @@ -2913,7 +2914,6 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) tag = le32_to_cpu(psmpPayload->tag); ccb = &pm8001_ha->ccb_info[tag]; - param = le32_to_cpu(psmpPayload->param); t = ccb->task; ts = &t->task_status; pm8001_dev = ccb->device; @@ -2928,7 +2928,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAM_STAT_GOOD; - if (pm8001_dev) + if (pm8001_dev) pm8001_dev->running_req--; break; case IO_ABORTED: @@ -3244,11 +3244,9 @@ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i) { struct pm8001_phy *phy = &pm8001_ha->phy[i]; struct asd_sas_phy *sas_phy = &phy->sas_phy; - struct sas_ha_struct *sas_ha; if (!phy->phy_attached) return; - sas_ha = pm8001_ha->sas; if (sas_phy->phy) { struct sas_phy *sphy = sas_phy->phy; sphy->negotiated_linkrate = sas_phy->linkrate; @@ -4562,7 +4560,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) phy_id = parent_dev->ex_dev.ex_phy->phy_id; else phy_id = pm8001_dev->attached_phy; @@ -4627,17 +4625,18 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, return ret; } -static u32 pm8001_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha) +static u32 pm8001_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) { - u32 value; #ifdef PM8001_USE_MSIX return 1; -#endif +#else + u32 value; + value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR); if (value) return 1; return 0; - +#endif } /** @@ -5123,7 +5122,7 @@ const struct pm8001_dispatch pm8001_8001_dispatch = { .chip_rst = pm8001_hw_chip_rst, .chip_iounmap = pm8001_chip_iounmap, .isr = pm8001_chip_isr, - .is_our_interupt = pm8001_chip_is_our_interupt, + .is_our_interrupt = pm8001_chip_is_our_interrupt, .isr_process_oq = process_oq, .interrupt_enable = pm8001_chip_interrupt_enable, .interrupt_disable = pm8001_chip_interrupt_disable, diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index a36060c23b37..3374f553c617 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -201,7 +201,7 @@ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque) if (unlikely(!pm8001_ha)) return IRQ_NONE; - if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha)) + if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) return IRQ_NONE; #ifdef PM8001_USE_TASKLET tasklet_schedule(&pm8001_ha->tasklet[irq_vector->irq_id]); @@ -224,7 +224,7 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) pm8001_ha = sha->lldd_ha; if (unlikely(!pm8001_ha)) return IRQ_NONE; - if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha)) + if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) return IRQ_NONE; #ifdef PM8001_USE_TASKLET diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 084f2fcced0a..dd38c356a1a4 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -634,7 +634,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) dev->lldd_dev = pm8001_device; pm8001_device->dev_type = dev->dev_type; pm8001_device->dcompletion = &completion; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_id; struct ex_phy *phy; for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys; @@ -740,8 +740,8 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, wait_for_completion(&task->slow_task->completion); if (pm8001_ha->chip_id != chip_8001) { pm8001_dev->setds_completion = &completion_setstate; - PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, - pm8001_dev, 0x01); + PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, + pm8001_dev, 0x01); wait_for_completion(&completion_setstate); } res = -TMF_RESP_FUNC_FAILED; @@ -1181,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task) return rc; } -/* mandatory SAM-3, still need free task/ccb info, abord the specified task */ +/* mandatory SAM-3, still need free task/ccb info, abort the specified task */ int pm8001_abort_task(struct sas_task *task) { unsigned long flags; diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index f88b0d33c385..ff17c6aff63d 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -103,7 +103,6 @@ do { \ #define PM8001_READ_VPD -#define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) #define IS_SPCV_12G(dev) ((dev->device == 0X8074) \ || (dev->device == 0X8076) \ || (dev->device == 0X8077) \ @@ -197,7 +196,7 @@ struct pm8001_dispatch { int (*chip_ioremap)(struct pm8001_hba_info *pm8001_ha); void (*chip_iounmap)(struct pm8001_hba_info *pm8001_ha); irqreturn_t (*isr)(struct pm8001_hba_info *pm8001_ha, u8 vec); - u32 (*is_our_interupt)(struct pm8001_hba_info *pm8001_ha); + u32 (*is_our_interrupt)(struct pm8001_hba_info *pm8001_ha); int (*isr_process_oq)(struct pm8001_hba_info *pm8001_ha, u8 vec); void (*interrupt_enable)(struct pm8001_hba_info *pm8001_ha, u8 vec); void (*interrupt_disable)(struct pm8001_hba_info *pm8001_ha, u8 vec); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 63e4f7d34d6c..1128d86d241a 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1316,7 +1316,7 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) { - u32 i; + u32 i; PM8001_INIT_DBG(pm8001_ha, pm8001_printk("chip reset start\n")); @@ -2066,7 +2066,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { if (!((t->dev->parent) && - (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) { + (dev_is_expander(t->dev->parent->dev_type)))) { for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++) @@ -4381,27 +4381,27 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, sata_cmd.len = cpu_to_le32(task->total_xfer_len); sata_cmd.esgl = 0; } - /* scsi cdb */ - sata_cmd.atapi_scsi_cdb[0] = - cpu_to_le32(((task->ata_task.atapi_packet[0]) | - (task->ata_task.atapi_packet[1] << 8) | - (task->ata_task.atapi_packet[2] << 16) | - (task->ata_task.atapi_packet[3] << 24))); - sata_cmd.atapi_scsi_cdb[1] = - cpu_to_le32(((task->ata_task.atapi_packet[4]) | - (task->ata_task.atapi_packet[5] << 8) | - (task->ata_task.atapi_packet[6] << 16) | - (task->ata_task.atapi_packet[7] << 24))); - sata_cmd.atapi_scsi_cdb[2] = - cpu_to_le32(((task->ata_task.atapi_packet[8]) | - (task->ata_task.atapi_packet[9] << 8) | - (task->ata_task.atapi_packet[10] << 16) | - (task->ata_task.atapi_packet[11] << 24))); - sata_cmd.atapi_scsi_cdb[3] = - cpu_to_le32(((task->ata_task.atapi_packet[12]) | - (task->ata_task.atapi_packet[13] << 8) | - (task->ata_task.atapi_packet[14] << 16) | - (task->ata_task.atapi_packet[15] << 24))); + /* scsi cdb */ + sata_cmd.atapi_scsi_cdb[0] = + cpu_to_le32(((task->ata_task.atapi_packet[0]) | + (task->ata_task.atapi_packet[1] << 8) | + (task->ata_task.atapi_packet[2] << 16) | + (task->ata_task.atapi_packet[3] << 24))); + sata_cmd.atapi_scsi_cdb[1] = + cpu_to_le32(((task->ata_task.atapi_packet[4]) | + (task->ata_task.atapi_packet[5] << 8) | + (task->ata_task.atapi_packet[6] << 16) | + (task->ata_task.atapi_packet[7] << 24))); + sata_cmd.atapi_scsi_cdb[2] = + cpu_to_le32(((task->ata_task.atapi_packet[8]) | + (task->ata_task.atapi_packet[9] << 8) | + (task->ata_task.atapi_packet[10] << 16) | + (task->ata_task.atapi_packet[11] << 24))); + sata_cmd.atapi_scsi_cdb[3] = + cpu_to_le32(((task->ata_task.atapi_packet[12]) | + (task->ata_task.atapi_packet[13] << 8) | + (task->ata_task.atapi_packet[14] << 16) | + (task->ata_task.atapi_packet[15] << 24))); } /* Check for read log for failed drive and return */ @@ -4561,7 +4561,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) phy_id = parent_dev->ex_dev.ex_phy->phy_id; else phy_id = pm8001_dev->attached_phy; @@ -4617,17 +4617,18 @@ static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, return pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); } -static u32 pm80xx_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha) +static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) { - u32 value; #ifdef PM8001_USE_MSIX return 1; -#endif +#else + u32 value; + value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR); if (value) return 1; return 0; - +#endif } /** @@ -4724,7 +4725,7 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = { .chip_rst = pm80xx_hw_chip_rst, .chip_iounmap = pm8001_chip_iounmap, .isr = pm80xx_chip_isr, - .is_our_interupt = pm80xx_chip_is_our_interupt, + .is_our_interrupt = pm80xx_chip_is_our_interrupt, .isr_process_oq = process_oq, .interrupt_enable = pm80xx_chip_interrupt_enable, .interrupt_disable = pm80xx_chip_interrupt_disable, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index e338d7a4f571..71ff3936da4f 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters * @@ -5,22 +6,6 @@ * PMC-Sierra Inc * * Copyright (C) 2008, 2009 PMC Sierra Inc - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA - * */ #include <linux/fs.h> #include <linux/init.h> @@ -3270,7 +3255,7 @@ static int pmcraid_copy_sglist( int direction ) { - struct scatterlist *scatterlist; + struct scatterlist *sg; void *kaddr; int bsize_elem; int i; @@ -3279,10 +3264,10 @@ static int pmcraid_copy_sglist( /* Determine the actual number of bytes per element */ bsize_elem = PAGE_SIZE * (1 << sglist->order); - scatterlist = sglist->scatterlist; + sg = sglist->scatterlist; - for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) { + struct page *page = sg_page(sg); kaddr = kmap(page); if (direction == DMA_TO_DEVICE) @@ -3297,11 +3282,11 @@ static int pmcraid_copy_sglist( return -EFAULT; } - scatterlist[i].length = bsize_elem; + sg->length = bsize_elem; } if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + struct page *page = sg_page(sg); kaddr = kmap(page); @@ -3312,7 +3297,7 @@ static int pmcraid_copy_sglist( kunmap(page); - scatterlist[i].length = len % bsize_elem; + sg->length = len % bsize_elem; } if (rc) { diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index 754ef30927e2..a4f7eb8f50a3 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * pmcraid.h -- PMC Sierra MaxRAID controller driver header file * @@ -5,20 +6,6 @@ * PMC-Sierra Inc * * Copyright (C) 2008, 2009 PMC Sierra Inc. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _PMCRAID_H diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index c182b5458f98..a406cc825426 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -590,7 +590,7 @@ static int ppa_completion(struct scsi_cmnd *cmd) if (cmd->SCp.buffer && !cmd->SCp.this_residual) { /* if scatter/gather, advance to the next segment */ if (cmd->SCp.buffers_residual--) { - cmd->SCp.buffer++; + cmd->SCp.buffer = sg_next(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); @@ -717,6 +717,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) } cmd->SCp.phase++; } + /* fall through */ case 2: /* Phase 2 - We are now talking to the scsi bus */ if (!ppa_select(dev, scmd_id(cmd))) { diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index 8d769138c01c..f75c0b5cd587 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PS3 BD/DVD/CD-ROM Storage Driver * * Copyright (C) 2007 Sony Computer Entertainment Inc. * Copyright 2007 Sony Corp. - * - * 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; version 2 of the License. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <linux/cdrom.h> diff --git a/drivers/scsi/qedf/Kconfig b/drivers/scsi/qedf/Kconfig index 943f5ee45807..7cd993be4e57 100644 --- a/drivers/scsi/qedf/Kconfig +++ b/drivers/scsi/qedf/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config QEDF tristate "QLogic QEDF 25/40/100Gb FCoE Initiator Driver Support" depends on PCI && SCSI diff --git a/drivers/scsi/qedf/Makefile b/drivers/scsi/qedf/Makefile index 414f2a772a5f..c46287826fb8 100644 --- a/drivers/scsi/qedf/Makefile +++ b/drivers/scsi/qedf/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_QEDF) := qedf.o qedf-y = qedf_dbg.o qedf_main.o qedf_io.o qedf_fip.o \ qedf_attr.o qedf_els.o drv_scsi_fw_funcs.o drv_fcoe_fw_funcs.o diff --git a/drivers/scsi/qedf/drv_fcoe_fw_funcs.c b/drivers/scsi/qedf/drv_fcoe_fw_funcs.c index 5bd10b534c99..747af96dd15c 100644 --- a/drivers/scsi/qedf/drv_fcoe_fw_funcs.c +++ b/drivers/scsi/qedf/drv_fcoe_fw_funcs.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "drv_fcoe_fw_funcs.h" #include "drv_scsi_fw_funcs.h" diff --git a/drivers/scsi/qedf/drv_fcoe_fw_funcs.h b/drivers/scsi/qedf/drv_fcoe_fw_funcs.h index 42fde55ac735..1ee31a5f063b 100644 --- a/drivers/scsi/qedf/drv_fcoe_fw_funcs.h +++ b/drivers/scsi/qedf/drv_fcoe_fw_funcs.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _FCOE_FW_FUNCS_H #define _FCOE_FW_FUNCS_H diff --git a/drivers/scsi/qedf/drv_scsi_fw_funcs.c b/drivers/scsi/qedf/drv_scsi_fw_funcs.c index 29a55257224f..3289b71031d6 100644 --- a/drivers/scsi/qedf/drv_scsi_fw_funcs.c +++ b/drivers/scsi/qedf/drv_scsi_fw_funcs.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "drv_scsi_fw_funcs.h" diff --git a/drivers/scsi/qedf/drv_scsi_fw_funcs.h b/drivers/scsi/qedf/drv_scsi_fw_funcs.h index bf102204fe56..6195f13dece8 100644 --- a/drivers/scsi/qedf/drv_scsi_fw_funcs.h +++ b/drivers/scsi/qedf/drv_scsi_fw_funcs.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _SCSI_FW_FUNCS_H #define _SCSI_FW_FUNCS_H diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 2c78d8fb9122..5a021217bfc9 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDFC_H_ #define _QEDFC_H_ @@ -35,9 +32,6 @@ #define QEDF_DESCR "QLogic FCoE Offload Driver" #define QEDF_MODULE_NAME "qedf" -#define QEDF_MIN_XID 0 -#define QEDF_MAX_SCSI_XID (NUM_TASKS_PER_CONNECTION - 1) -#define QEDF_MAX_ELS_XID 4095 #define QEDF_FLOGI_RETRY_CNT 3 #define QEDF_RPORT_RETRY_CNT 255 #define QEDF_MAX_SESSIONS 1024 @@ -52,8 +46,8 @@ sizeof(struct fc_frame_header)) #define QEDF_MAX_NPIV 64 #define QEDF_TM_TIMEOUT 10 -#define QEDF_ABORT_TIMEOUT 10 -#define QEDF_CLEANUP_TIMEOUT 10 +#define QEDF_ABORT_TIMEOUT (10 * 1000) +#define QEDF_CLEANUP_TIMEOUT 1 #define QEDF_MAX_CDB_LEN 16 #define UPSTREAM_REMOVE 1 @@ -85,6 +79,7 @@ struct qedf_els_cb_arg { }; enum qedf_ioreq_event { + QEDF_IOREQ_EV_NONE, QEDF_IOREQ_EV_ABORT_SUCCESS, QEDF_IOREQ_EV_ABORT_FAILED, QEDF_IOREQ_EV_SEND_RRQ, @@ -105,7 +100,6 @@ struct qedf_ioreq { struct list_head link; uint16_t xid; struct scsi_cmnd *sc_cmd; - bool use_slowpath; /* Use slow SGL for this I/O */ #define QEDF_SCSI_CMD 1 #define QEDF_TASK_MGMT_CMD 2 #define QEDF_ABTS 3 @@ -117,22 +111,43 @@ struct qedf_ioreq { #define QEDF_CMD_IN_ABORT 0x1 #define QEDF_CMD_IN_CLEANUP 0x2 #define QEDF_CMD_SRR_SENT 0x3 +#define QEDF_CMD_DIRTY 0x4 +#define QEDF_CMD_ERR_SCSI_DONE 0x5 u8 io_req_flags; uint8_t tm_flags; struct qedf_rport *fcport; +#define QEDF_CMD_ST_INACTIVE 0 +#define QEDFC_CMD_ST_IO_ACTIVE 1 +#define QEDFC_CMD_ST_ABORT_ACTIVE 2 +#define QEDFC_CMD_ST_ABORT_ACTIVE_EH 3 +#define QEDFC_CMD_ST_CLEANUP_ACTIVE 4 +#define QEDFC_CMD_ST_CLEANUP_ACTIVE_EH 5 +#define QEDFC_CMD_ST_RRQ_ACTIVE 6 +#define QEDFC_CMD_ST_RRQ_WAIT 7 +#define QEDFC_CMD_ST_OXID_RETIRE_WAIT 8 +#define QEDFC_CMD_ST_TMF_ACTIVE 9 +#define QEDFC_CMD_ST_DRAIN_ACTIVE 10 +#define QEDFC_CMD_ST_CLEANED 11 +#define QEDFC_CMD_ST_ELS_ACTIVE 12 + atomic_t state; unsigned long flags; enum qedf_ioreq_event event; size_t data_xfer_len; + /* ID: 001: Alloc cmd (qedf_alloc_cmd) */ + /* ID: 002: Initiate ABTS (qedf_initiate_abts) */ + /* ID: 003: For RRQ (qedf_process_abts_compl) */ struct kref refcount; struct qedf_cmd_mgr *cmd_mgr; struct io_bdt *bd_tbl; struct delayed_work timeout_work; struct completion tm_done; struct completion abts_done; + struct completion cleanup_done; struct e4_fcoe_task_context *task; struct fcoe_task_params *task_params; struct scsi_sgl_task_params *sgl_task_params; int idx; + int lun; /* * Need to allocate enough room for both sense data and FCP response data * which has a max length of 8 bytes according to spec. @@ -155,9 +170,9 @@ struct qedf_ioreq { int fp_idx; unsigned int cpu; unsigned int int_cpu; -#define QEDF_IOREQ_SLOW_SGE 0 -#define QEDF_IOREQ_SINGLE_SGE 1 -#define QEDF_IOREQ_FAST_SGE 2 +#define QEDF_IOREQ_UNKNOWN_SGE 1 +#define QEDF_IOREQ_SLOW_SGE 2 +#define QEDF_IOREQ_FAST_SGE 3 u8 sge_type; struct delayed_work rrq_work; @@ -172,6 +187,8 @@ struct qedf_ioreq { * during some form of error processing. */ bool return_scsi_cmd_on_abts; + + unsigned int alloc; }; extern struct workqueue_struct *qedf_io_wq; @@ -181,7 +198,10 @@ struct qedf_rport { #define QEDF_RPORT_SESSION_READY 1 #define QEDF_RPORT_UPLOADING_CONNECTION 2 #define QEDF_RPORT_IN_RESET 3 +#define QEDF_RPORT_IN_LUN_RESET 4 +#define QEDF_RPORT_IN_TARGET_RESET 5 unsigned long flags; + int lun_reset_lun; unsigned long retry_delay_timestamp; struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -191,6 +211,7 @@ struct qedf_rport { void __iomem *p_doorbell; /* Send queue management */ atomic_t free_sqes; + atomic_t ios_to_queue; atomic_t num_active_ios; struct fcoe_wqe *sq; dma_addr_t sq_dma; @@ -295,8 +316,6 @@ struct qedf_ctx { #define QEDF_DCBX_PENDING 0 #define QEDF_DCBX_DONE 1 atomic_t dcbx; - uint16_t max_scsi_xid; - uint16_t max_els_xid; #define QEDF_NULL_VLAN_ID -1 #define QEDF_FALLBACK_VLAN 1002 #define QEDF_DEFAULT_PRIO 3 @@ -371,7 +390,6 @@ struct qedf_ctx { u32 slow_sge_ios; u32 fast_sge_ios; - u32 single_sge_ios; uint8_t *grcdump; uint32_t grcdump_size; @@ -396,6 +414,8 @@ struct qedf_ctx { u8 target_resets; u8 task_set_fulls; u8 busy; + /* Used for flush routine */ + struct mutex flush_mutex; }; struct io_bdt { @@ -435,6 +455,12 @@ static inline void qedf_stop_all_io(struct qedf_ctx *qedf) /* * Externs */ + +/* + * (QEDF_LOG_NPIV | QEDF_LOG_SESS | QEDF_LOG_LPORT | QEDF_LOG_ELS | QEDF_LOG_MQ + * | QEDF_LOG_IO | QEDF_LOG_UNSOL | QEDF_LOG_SCSI_TM | QEDF_LOG_MP_REQ | + * QEDF_LOG_EVT | QEDF_LOG_CONN | QEDF_LOG_DISC | QEDF_LOG_INFO) + */ #define QEDF_DEFAULT_LOG_MASK 0x3CFB6 extern const struct qed_fcoe_ops *qed_ops; extern uint qedf_dump_frames; @@ -494,7 +520,7 @@ extern void qedf_set_vlan_id(struct qedf_ctx *qedf, int vlan_id); extern void qedf_create_sysfs_ctx_attr(struct qedf_ctx *qedf); extern void qedf_remove_sysfs_ctx_attr(struct qedf_ctx *qedf); extern void qedf_capture_grc_dump(struct qedf_ctx *qedf); -extern void qedf_wait_for_upload(struct qedf_ctx *qedf); +bool qedf_wait_for_upload(struct qedf_ctx *qedf); extern void qedf_process_unsol_compl(struct qedf_ctx *qedf, uint16_t que_idx, struct fcoe_cqe *cqe); extern void qedf_restart_rport(struct qedf_rport *fcport); @@ -508,6 +534,8 @@ extern void qedf_get_protocol_tlv_data(void *dev, void *data); extern void qedf_fp_io_handler(struct work_struct *work); extern void qedf_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data); extern void qedf_wq_grcdump(struct work_struct *work); +void qedf_stag_change_work(struct work_struct *work); +void qedf_ctx_soft_reset(struct fc_lport *lport); #define FCOE_WORD_TO_BYTE 4 #define QEDF_MAX_TASK_NUM 0xFFFF diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c index 0487b7237104..d995f72a6759 100644 --- a/drivers/scsi/qedf/qedf_attr.c +++ b/drivers/scsi/qedf/qedf_attr.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "qedf.h" diff --git a/drivers/scsi/qedf/qedf_dbg.c b/drivers/scsi/qedf/qedf_dbg.c index f2397ee9ba69..e0387e495261 100644 --- a/drivers/scsi/qedf/qedf_dbg.c +++ b/drivers/scsi/qedf/qedf_dbg.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "qedf_dbg.h" #include <linux/vmalloc.h> @@ -15,10 +12,6 @@ qedf_dbg_err(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -27,9 +20,9 @@ qedf_dbg_err(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)), - nfunc, line, qedf->host_no, &vaf); + func, line, qedf->host_no, &vaf); else - pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_err("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); va_end(va); } @@ -40,10 +33,6 @@ qedf_dbg_warn(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -55,9 +44,9 @@ qedf_dbg_warn(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)), - nfunc, line, qedf->host_no, &vaf); + func, line, qedf->host_no, &vaf); else - pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_warn("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); @@ -69,10 +58,6 @@ qedf_dbg_notice(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -84,10 +69,10 @@ qedf_dbg_notice(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_notice("[%s]:[%s:%d]:%d: %pV", - dev_name(&(qedf->pdev->dev)), nfunc, line, + dev_name(&(qedf->pdev->dev)), func, line, qedf->host_no, &vaf); else - pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_notice("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); @@ -99,10 +84,6 @@ qedf_dbg_info(struct qedf_dbg_ctx *qedf, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -114,9 +95,9 @@ qedf_dbg_info(struct qedf_dbg_ctx *qedf, const char *func, u32 line, if (likely(qedf) && likely(qedf->pdev)) pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)), - nfunc, line, qedf->host_no, &vaf); + func, line, qedf->host_no, &vaf); else - pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_info("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h index dd0109653aa3..d979f095aeda 100644 --- a/drivers/scsi/qedf/qedf_dbg.h +++ b/drivers/scsi/qedf/qedf_dbg.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDF_DBG_H_ #define _QEDF_DBG_H_ diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index a32d8ee4666e..d905a307302d 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 QLogic Corporation - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifdef CONFIG_DEBUG_FS @@ -293,6 +290,33 @@ qedf_dbg_io_trace_open(struct inode *inode, struct file *file) return single_open(file, qedf_io_trace_show, qedf); } +/* Based on fip_state enum from libfcoe.h */ +static char *fip_state_names[] = { + "FIP_ST_DISABLED", + "FIP_ST_LINK_WAIT", + "FIP_ST_AUTO", + "FIP_ST_NON_FIP", + "FIP_ST_ENABLED", + "FIP_ST_VNMP_START", + "FIP_ST_VNMP_PROBE1", + "FIP_ST_VNMP_PROBE2", + "FIP_ST_VNMP_CLAIM", + "FIP_ST_VNMP_UP", +}; + +/* Based on fc_rport_state enum from libfc.h */ +static char *fc_rport_state_names[] = { + "RPORT_ST_INIT", + "RPORT_ST_FLOGI", + "RPORT_ST_PLOGI_WAIT", + "RPORT_ST_PLOGI", + "RPORT_ST_PRLI", + "RPORT_ST_RTV", + "RPORT_ST_READY", + "RPORT_ST_ADISC", + "RPORT_ST_DELETE", +}; + static int qedf_driver_stats_show(struct seq_file *s, void *unused) { @@ -300,10 +324,28 @@ qedf_driver_stats_show(struct seq_file *s, void *unused) struct qedf_rport *fcport; struct fc_rport_priv *rdata; + seq_printf(s, "Host WWNN/WWPN: %016llx/%016llx\n", + qedf->wwnn, qedf->wwpn); + seq_printf(s, "Host NPortID: %06x\n", qedf->lport->port_id); + seq_printf(s, "Link State: %s\n", atomic_read(&qedf->link_state) ? + "Up" : "Down"); + seq_printf(s, "Logical Link State: %s\n", qedf->lport->link_up ? + "Up" : "Down"); + seq_printf(s, "FIP state: %s\n", fip_state_names[qedf->ctlr.state]); + seq_printf(s, "FIP VLAN ID: %d\n", qedf->vlan_id & 0xfff); + seq_printf(s, "FIP 802.1Q Priority: %d\n", qedf->prio); + if (qedf->ctlr.sel_fcf) { + seq_printf(s, "FCF WWPN: %016llx\n", + qedf->ctlr.sel_fcf->switch_name); + seq_printf(s, "FCF MAC: %pM\n", qedf->ctlr.sel_fcf->fcf_mac); + } else { + seq_puts(s, "FCF not selected\n"); + } + + seq_puts(s, "\nSGE stats:\n\n"); seq_printf(s, "cmg_mgr free io_reqs: %d\n", atomic_read(&qedf->cmd_mgr->free_list_cnt)); seq_printf(s, "slow SGEs: %d\n", qedf->slow_sge_ios); - seq_printf(s, "single SGEs: %d\n", qedf->single_sge_ios); seq_printf(s, "fast SGEs: %d\n\n", qedf->fast_sge_ios); seq_puts(s, "Offloaded ports:\n\n"); @@ -313,9 +355,12 @@ qedf_driver_stats_show(struct seq_file *s, void *unused) rdata = fcport->rdata; if (rdata == NULL) continue; - seq_printf(s, "%06x: free_sqes: %d, num_active_ios: %d\n", - rdata->ids.port_id, atomic_read(&fcport->free_sqes), - atomic_read(&fcport->num_active_ios)); + seq_printf(s, "%016llx/%016llx/%06x: state=%s, free_sqes=%d, num_active_ios=%d\n", + rdata->rport->node_name, rdata->rport->port_name, + rdata->ids.port_id, + fc_rport_state_names[rdata->rp_state], + atomic_read(&fcport->free_sqes), + atomic_read(&fcport->num_active_ios)); } rcu_read_unlock(); @@ -361,7 +406,6 @@ qedf_dbg_clear_stats_cmd_write(struct file *filp, /* Clear stat counters exposed by 'stats' node */ qedf->slow_sge_ios = 0; - qedf->single_sge_ios = 0; qedf->fast_sge_ios = 0; return count; diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index 04f0c4d2e256..5996f68fbf2b 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "qedf.h" @@ -23,8 +20,6 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op, int rc = 0; uint32_t did, sid; uint16_t xid; - uint32_t start_time = jiffies / HZ; - uint32_t current_time; struct fcoe_wqe *sqe; unsigned long flags; u16 sqe_idx; @@ -59,18 +54,12 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op, goto els_err; } -retry_els: els_req = qedf_alloc_cmd(fcport, QEDF_ELS); if (!els_req) { - current_time = jiffies / HZ; - if ((current_time - start_time) > 10) { - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, - "els: Failed els 0x%x\n", op); - rc = -ENOMEM; - goto els_err; - } - mdelay(20 * USEC_PER_MSEC); - goto retry_els; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS, + "Failed to alloc ELS request 0x%x\n", op); + rc = -ENOMEM; + goto els_err; } QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "initiate_els els_req = " @@ -143,6 +132,8 @@ retry_els: QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Ringing doorbell for ELS " "req\n"); qedf_ring_doorbell(fcport); + set_bit(QEDF_CMD_OUTSTANDING, &els_req->flags); + spin_unlock_irqrestore(&fcport->rport_lock, flags); els_err: return rc; @@ -151,21 +142,16 @@ els_err: void qedf_process_els_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *els_req) { - struct fcoe_task_context *task_ctx; - struct scsi_cmnd *sc_cmd; - uint16_t xid; struct fcoe_cqe_midpath_info *mp_info; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Entered with xid = 0x%x" " cmd_type = %d.\n", els_req->xid, els_req->cmd_type); + clear_bit(QEDF_CMD_OUTSTANDING, &els_req->flags); + /* Kill the ELS timer */ cancel_delayed_work(&els_req->timeout_work); - xid = els_req->xid; - task_ctx = qedf_get_task_mem(&qedf->tasks, xid); - sc_cmd = els_req->sc_cmd; - /* Get ELS response length from CQE */ mp_info = &cqe->cqe_info.midpath_info; els_req->mp_req.resp_len = mp_info->data_placement_size; @@ -205,8 +191,12 @@ static void qedf_rrq_compl(struct qedf_els_cb_arg *cb_arg) " orig xid = 0x%x, rrq_xid = 0x%x, refcount=%d\n", orig_io_req, orig_io_req->xid, rrq_req->xid, refcount); - /* This should return the aborted io_req to the command pool */ - if (orig_io_req) + /* + * This should return the aborted io_req to the command pool. Note that + * we need to check the refcound in case the original request was + * flushed but we get a completion on this xid. + */ + if (orig_io_req && refcount > 0) kref_put(&orig_io_req->refcount, qedf_release_cmd); out_free: @@ -233,6 +223,7 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) uint32_t sid; uint32_t r_a_tov; int rc; + int refcount; if (!aborted_io_req) { QEDF_ERR(NULL, "abort_io_req is NULL.\n"); @@ -241,6 +232,15 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) fcport = aborted_io_req->fcport; + if (!fcport) { + refcount = kref_read(&aborted_io_req->refcount); + QEDF_ERR(NULL, + "RRQ work was queued prior to a flush xid=0x%x, refcount=%d.\n", + aborted_io_req->xid, refcount); + kref_put(&aborted_io_req->refcount, qedf_release_cmd); + return -EINVAL; + } + /* Check that fcport is still offloaded */ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(NULL, "fcport is no longer offloaded.\n"); @@ -253,6 +253,19 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req) } qedf = fcport->qedf; + + /* + * Sanity check that we can send a RRQ to make sure that refcount isn't + * 0 + */ + refcount = kref_read(&aborted_io_req->refcount); + if (refcount != 1) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS, + "refcount for xid=%x io_req=%p refcount=%d is not 1.\n", + aborted_io_req->xid, aborted_io_req, refcount); + return -EINVAL; + } + lport = qedf->lport; sid = fcport->sid; r_a_tov = lport->r_a_tov; @@ -335,32 +348,49 @@ void qedf_restart_rport(struct qedf_rport *fcport) struct fc_lport *lport; struct fc_rport_priv *rdata; u32 port_id; + unsigned long flags; if (!fcport) return; + spin_lock_irqsave(&fcport->rport_lock, flags); if (test_bit(QEDF_RPORT_IN_RESET, &fcport->flags) || !test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&(fcport->qedf->dbg_ctx), "fcport %p already in reset or not offloaded.\n", fcport); + spin_unlock_irqrestore(&fcport->rport_lock, flags); return; } /* Set that we are now in reset */ set_bit(QEDF_RPORT_IN_RESET, &fcport->flags); + spin_unlock_irqrestore(&fcport->rport_lock, flags); rdata = fcport->rdata; - if (rdata) { + if (rdata && !kref_get_unless_zero(&rdata->kref)) { + fcport->rdata = NULL; + rdata = NULL; + } + + if (rdata && rdata->rp_state == RPORT_ST_READY) { lport = fcport->qedf->lport; port_id = rdata->ids.port_id; QEDF_ERR(&(fcport->qedf->dbg_ctx), "LOGO port_id=%x.\n", port_id); fc_rport_logoff(rdata); + kref_put(&rdata->kref, fc_rport_destroy); + mutex_lock(&lport->disc.disc_mutex); /* Recreate the rport and log back in */ rdata = fc_rport_create(lport, port_id); - if (rdata) + if (rdata) { + mutex_unlock(&lport->disc.disc_mutex); fc_rport_login(rdata); + fcport->rdata = rdata; + } else { + mutex_unlock(&lport->disc.disc_mutex); + fcport->rdata = NULL; + } } clear_bit(QEDF_RPORT_IN_RESET, &fcport->flags); } @@ -569,7 +599,7 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl) struct qedf_rport *fcport; struct fc_lport *lport; struct qedf_els_cb_arg *cb_arg = NULL; - u32 sid, r_a_tov; + u32 r_a_tov; int rc; if (!orig_io_req) { @@ -595,7 +625,6 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl) qedf = fcport->qedf; lport = qedf->lport; - sid = fcport->sid; r_a_tov = lport->r_a_tov; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Sending SRR orig_io=%p, " diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c index 3fd3af799b3d..362d2bed72fb 100644 --- a/drivers/scsi/qedf/qedf_fip.c +++ b/drivers/scsi/qedf/qedf_fip.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/if_ether.h> #include <linux/if_vlan.h> @@ -19,17 +16,16 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf) { struct sk_buff *skb; char *eth_fr; - int fr_len; struct fip_vlan *vlan; #define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 }) static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS; unsigned long flags = 0; + int rc = -1; skb = dev_alloc_skb(sizeof(struct fip_vlan)); if (!skb) return; - fr_len = sizeof(*vlan); eth_fr = (char *)skb->data; vlan = (struct fip_vlan *)eth_fr; @@ -68,7 +64,13 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf) } set_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &flags); - qed_ops->ll2->start_xmit(qedf->cdev, skb, flags); + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, flags); + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); + kfree_skb(skb); + return; + } + } static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf, @@ -95,6 +97,12 @@ static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf, rlen -= dlen; } + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Dropping VLAN response as link is down.\n"); + return; + } + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, " "vid=0x%x.\n", vid); @@ -114,6 +122,7 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) struct fip_header *fiph; u16 op, vlan_tci = 0; u8 sub; + int rc = -1; if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) { QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n"); @@ -142,9 +151,16 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, false); - qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); + kfree_skb(skb); + return; + } } +static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS; + /* Process incoming FIP frames. */ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) { @@ -157,20 +173,37 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) size_t rlen, dlen; u16 op; u8 sub; - bool do_reset = false; + bool fcf_valid = false; + /* Default is to handle CVL regardless of fabric id descriptor */ + bool fabric_id_valid = true; + bool fc_wwpn_valid = false; + u64 switch_name; + u16 vlan = 0; eth_hdr = (struct ethhdr *)skb_mac_header(skb); fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); op = ntohs(fiph->fip_op); sub = fiph->fip_subcode; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: " - "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph, - eth_hdr->h_source, op, sub); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x", + skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op, + sub, vlan); if (qedf_dump_frames) print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, false); + if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) && + !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) && + !ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n", + op, eth_hdr->h_dest, qedf->mac, + qedf->data_src_addr); + kfree_skb(skb); + return; + } + /* Handle FIP VLAN resp in the driver */ if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) { qedf_fcoe_process_vlan_resp(qedf, skb); @@ -199,25 +232,36 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) switch (desc->fip_dtype) { case FIP_DT_MAC: mp = (struct fip_mac_desc *)desc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "fd_mac=%pM\n", mp->fd_mac); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Switch fd_mac=%pM.\n", mp->fd_mac); if (ether_addr_equal(mp->fd_mac, qedf->ctlr.sel_fcf->fcf_mac)) - do_reset = true; + fcf_valid = true; break; case FIP_DT_NAME: wp = (struct fip_wwn_desc *)desc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "fc_wwpn=%016llx.\n", - get_unaligned_be64(&wp->fd_wwn)); + switch_name = get_unaligned_be64(&wp->fd_wwn); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n", + switch_name, + qedf->ctlr.sel_fcf->switch_name); + if (switch_name == + qedf->ctlr.sel_fcf->switch_name) + fc_wwpn_valid = true; break; case FIP_DT_VN_ID: vp = (struct fip_vn_desc *)desc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id)); - if (ntoh24(vp->fd_fc_id) == + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "vx_port fd_fc_id=%x fd_mac=%pM.\n", + ntoh24(vp->fd_fc_id), vp->fd_mac); + /* Check vx_port fabric ID */ + if (ntoh24(vp->fd_fc_id) != qedf->lport->port_id) - do_reset = true; + fabric_id_valid = false; + /* Check vx_port MAC */ + if (!ether_addr_equal(vp->fd_mac, + qedf->data_src_addr)) + fabric_id_valid = false; break; default: /* Ignore anything else */ @@ -227,13 +271,11 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) rlen -= dlen; } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "do_reset=%d.\n", do_reset); - if (do_reset) { - fcoe_ctlr_link_down(&qedf->ctlr); - qedf_wait_for_upload(qedf); - fcoe_ctlr_link_up(&qedf->ctlr); - } + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n", + fcf_valid, fabric_id_valid, fc_wwpn_valid); + if (fcf_valid && fabric_id_valid && fc_wwpn_valid) + qedf_ctx_soft_reset(qedf->lport); kfree_skb(skb); } else { /* Everything else is handled by libfcoe */ diff --git a/drivers/scsi/qedf/qedf_hsi.h b/drivers/scsi/qedf/qedf_hsi.h index f6f634e48d69..ecd5cb53b750 100644 --- a/drivers/scsi/qedf/qedf_hsi.h +++ b/drivers/scsi/qedf/qedf_hsi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef __QEDF_HSI__ #define __QEDF_HSI__ diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index 6ca583bdde23..d881e822f92c 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/spinlock.h> #include <linux/vmalloc.h> @@ -43,8 +40,9 @@ static void qedf_cmd_timeout(struct work_struct *work) switch (io_req->cmd_type) { case QEDF_ABTS: if (qedf == NULL) { - QEDF_INFO(NULL, QEDF_LOG_IO, "qedf is NULL for xid=0x%x.\n", - io_req->xid); + QEDF_INFO(NULL, QEDF_LOG_IO, + "qedf is NULL for ABTS xid=0x%x.\n", + io_req->xid); return; } @@ -61,6 +59,9 @@ static void qedf_cmd_timeout(struct work_struct *work) */ kref_put(&io_req->refcount, qedf_release_cmd); + /* Clear in abort bit now that we're done with the command */ + clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); + /* * Now that the original I/O and the ABTS are complete see * if we need to reconnect to the target. @@ -68,6 +69,15 @@ static void qedf_cmd_timeout(struct work_struct *work) qedf_restart_rport(fcport); break; case QEDF_ELS: + if (!qedf) { + QEDF_INFO(NULL, QEDF_LOG_IO, + "qedf is NULL for ELS xid=0x%x.\n", + io_req->xid); + return; + } + /* ELS request no longer outstanding since it timed out */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + kref_get(&io_req->refcount); /* * Don't attempt to clean an ELS timeout as any subseqeunt @@ -103,7 +113,7 @@ void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr) struct io_bdt *bdt_info; struct qedf_ctx *qedf = cmgr->qedf; size_t bd_tbl_sz; - u16 min_xid = QEDF_MIN_XID; + u16 min_xid = 0; u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1); int num_ios; int i; @@ -157,6 +167,7 @@ static void qedf_handle_rrq(struct work_struct *work) struct qedf_ioreq *io_req = container_of(work, struct qedf_ioreq, rrq_work.work); + atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_ACTIVE); qedf_send_rrq(io_req); } @@ -169,7 +180,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) u16 xid; int i; int num_ios; - u16 min_xid = QEDF_MIN_XID; + u16 min_xid = 0; u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1); /* Make sure num_queues is already set before calling this function */ @@ -201,7 +212,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) /* * Initialize I/O request fields. */ - xid = QEDF_MIN_XID; + xid = 0; for (i = 0; i < num_ios; i++) { io_req = &cmgr->cmds[i]; @@ -329,7 +340,7 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) cmd_mgr->idx = 0; /* Check to make sure command was previously freed */ - if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) + if (!io_req->alloc) break; } @@ -338,7 +349,14 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) goto out_failed; } - set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + if (test_bit(QEDF_CMD_DIRTY, &io_req->flags)) + QEDF_ERR(&qedf->dbg_ctx, + "io_req found to be dirty ox_id = 0x%x.\n", + io_req->xid); + + /* Clear any flags now that we've reallocated the xid */ + io_req->flags = 0; + io_req->alloc = 1; spin_unlock_irqrestore(&cmd_mgr->lock, flags); atomic_inc(&fcport->num_active_ios); @@ -349,8 +367,13 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type) io_req->cmd_mgr = cmd_mgr; io_req->fcport = fcport; + /* Clear any stale sc_cmd back pointer */ + io_req->sc_cmd = NULL; + io_req->lun = -1; + /* Hold the io_req against deletion */ - kref_init(&io_req->refcount); + kref_init(&io_req->refcount); /* ID: 001 */ + atomic_set(&io_req->state, QEDFC_CMD_ST_IO_ACTIVE); /* Bind io_bdt for this io_req */ /* Have a static link between io_req and io_bdt_pool */ @@ -412,6 +435,10 @@ void qedf_release_cmd(struct kref *ref) container_of(ref, struct qedf_ioreq, refcount); struct qedf_cmd_mgr *cmd_mgr = io_req->cmd_mgr; struct qedf_rport *fcport = io_req->fcport; + unsigned long flags; + + if (io_req->cmd_type == QEDF_SCSI_CMD) + WARN_ON(io_req->sc_cmd); if (io_req->cmd_type == QEDF_ELS || io_req->cmd_type == QEDF_TASK_MGMT_CMD) @@ -419,36 +446,20 @@ void qedf_release_cmd(struct kref *ref) atomic_inc(&cmd_mgr->free_list_cnt); atomic_dec(&fcport->num_active_ios); + atomic_set(&io_req->state, QEDF_CMD_ST_INACTIVE); if (atomic_read(&fcport->num_active_ios) < 0) QEDF_WARN(&(fcport->qedf->dbg_ctx), "active_ios < 0.\n"); /* Increment task retry identifier now that the request is released */ io_req->task_retry_identifier++; + io_req->fcport = NULL; - clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); -} - -static int qedf_split_bd(struct qedf_ioreq *io_req, u64 addr, int sg_len, - int bd_index) -{ - struct scsi_sge *bd = io_req->bd_tbl->bd_tbl; - int frag_size, sg_frags; - - sg_frags = 0; - while (sg_len) { - if (sg_len > QEDF_BD_SPLIT_SZ) - frag_size = QEDF_BD_SPLIT_SZ; - else - frag_size = sg_len; - bd[bd_index + sg_frags].sge_addr.lo = U64_LO(addr); - bd[bd_index + sg_frags].sge_addr.hi = U64_HI(addr); - bd[bd_index + sg_frags].sge_len = (uint16_t)frag_size; - - addr += (u64)frag_size; - sg_frags++; - sg_len -= frag_size; - } - return sg_frags; + clear_bit(QEDF_CMD_DIRTY, &io_req->flags); + io_req->cpu = 0; + spin_lock_irqsave(&cmd_mgr->lock, flags); + io_req->fcport = NULL; + io_req->alloc = 0; + spin_unlock_irqrestore(&cmd_mgr->lock, flags); } static int qedf_map_sg(struct qedf_ioreq *io_req) @@ -462,75 +473,45 @@ static int qedf_map_sg(struct qedf_ioreq *io_req) int byte_count = 0; int sg_count = 0; int bd_count = 0; - int sg_frags; - unsigned int sg_len; + u32 sg_len; u64 addr, end_addr; - int i; + int i = 0; sg_count = dma_map_sg(&qedf->pdev->dev, scsi_sglist(sc), scsi_sg_count(sc), sc->sc_data_direction); - sg = scsi_sglist(sc); - /* - * New condition to send single SGE as cached-SGL with length less - * than 64k. - */ - if ((sg_count == 1) && (sg_dma_len(sg) <= - QEDF_MAX_SGLEN_FOR_CACHESGL)) { - sg_len = sg_dma_len(sg); - addr = (u64)sg_dma_address(sg); - - bd[bd_count].sge_addr.lo = (addr & 0xffffffff); - bd[bd_count].sge_addr.hi = (addr >> 32); - bd[bd_count].sge_len = (u16)sg_len; + io_req->sge_type = QEDF_IOREQ_UNKNOWN_SGE; - return ++bd_count; - } + if (sg_count <= 8 || io_req->io_req_flags == QEDF_READ) + io_req->sge_type = QEDF_IOREQ_FAST_SGE; scsi_for_each_sg(sc, sg, sg_count, i) { - sg_len = sg_dma_len(sg); + sg_len = (u32)sg_dma_len(sg); addr = (u64)sg_dma_address(sg); end_addr = (u64)(addr + sg_len); /* - * First s/g element in the list so check if the end_addr - * is paged aligned. Also check to make sure the length is - * at least page size. - */ - if ((i == 0) && (sg_count > 1) && - ((end_addr % QEDF_PAGE_SIZE) || - sg_len < QEDF_PAGE_SIZE)) - io_req->use_slowpath = true; - /* - * Last s/g element so check if the start address is paged - * aligned. - */ - else if ((i == (sg_count - 1)) && (sg_count > 1) && - (addr % QEDF_PAGE_SIZE)) - io_req->use_slowpath = true; - /* * Intermediate s/g element so check if start and end address - * is page aligned. + * is page aligned. Only required for writes and only if the + * number of scatter/gather elements is 8 or more. */ - else if ((i != 0) && (i != (sg_count - 1)) && - ((addr % QEDF_PAGE_SIZE) || (end_addr % QEDF_PAGE_SIZE))) - io_req->use_slowpath = true; + if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE && (i) && + (i != (sg_count - 1)) && sg_len < QEDF_PAGE_SIZE) + io_req->sge_type = QEDF_IOREQ_SLOW_SGE; - if (sg_len > QEDF_MAX_BD_LEN) { - sg_frags = qedf_split_bd(io_req, addr, sg_len, - bd_count); - } else { - sg_frags = 1; - bd[bd_count].sge_addr.lo = U64_LO(addr); - bd[bd_count].sge_addr.hi = U64_HI(addr); - bd[bd_count].sge_len = (uint16_t)sg_len; - } + bd[bd_count].sge_addr.lo = cpu_to_le32(U64_LO(addr)); + bd[bd_count].sge_addr.hi = cpu_to_le32(U64_HI(addr)); + bd[bd_count].sge_len = cpu_to_le32(sg_len); - bd_count += sg_frags; + bd_count++; byte_count += sg_len; } + /* To catch a case where FAST and SLOW nothing is set, set FAST */ + if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE) + io_req->sge_type = QEDF_IOREQ_FAST_SGE; + if (byte_count != scsi_bufflen(sc)) QEDF_ERR(&(qedf->dbg_ctx), "byte_count = %d != " "scsi_bufflen = %d, task_id = 0x%x.\n", byte_count, @@ -655,8 +636,10 @@ static void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport, io_req->sgl_task_params->num_sges = bd_count; io_req->sgl_task_params->total_buffer_size = scsi_bufflen(io_req->sc_cmd); - io_req->sgl_task_params->small_mid_sge = - io_req->use_slowpath; + if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE) + io_req->sgl_task_params->small_mid_sge = 1; + else + io_req->sgl_task_params->small_mid_sge = 0; } /* Fill in physical address of sense buffer */ @@ -679,16 +662,10 @@ static void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport, io_req->task_retry_identifier, fcp_cmnd); /* Increment SGL type counters */ - if (bd_count == 1) { - qedf->single_sge_ios++; - io_req->sge_type = QEDF_IOREQ_SINGLE_SGE; - } else if (io_req->use_slowpath) { + if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE) qedf->slow_sge_ios++; - io_req->sge_type = QEDF_IOREQ_SLOW_SGE; - } else { + else qedf->fast_sge_ios++; - io_req->sge_type = QEDF_IOREQ_FAST_SGE; - } } void qedf_init_mp_task(struct qedf_ioreq *io_req, @@ -770,9 +747,6 @@ void qedf_init_mp_task(struct qedf_ioreq *io_req, &task_fc_hdr, &tx_sgl_task_params, &rx_sgl_task_params, 0); - - /* Midpath requests always consume 1 SGE */ - qedf->single_sge_ios++; } /* Presumed that fcport->rport_lock is held */ @@ -804,10 +778,18 @@ void qedf_ring_doorbell(struct qedf_rport *fcport) FCOE_DB_DATA_AGG_VAL_SEL_SHIFT; dbell.sq_prod = fcport->fw_sq_prod_idx; + /* wmb makes sure that the BDs data is updated before updating the + * producer, otherwise FW may read old data from the BDs. + */ + wmb(); + barrier(); writel(*(u32 *)&dbell, fcport->p_doorbell); - /* Make sure SQ index is updated so f/w prcesses requests in order */ + /* + * Fence required to flush the write combined buffer, since another + * CPU may write to the same doorbell address and data may be lost + * due to relaxed order nature of write combined bar. + */ wmb(); - mmiowb(); } static void qedf_trace_io(struct qedf_rport *fcport, struct qedf_ioreq *io_req, @@ -872,7 +854,7 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) /* Initialize rest of io_req fileds */ io_req->data_xfer_len = scsi_bufflen(sc_cmd); sc_cmd->SCp.ptr = (char *)io_req; - io_req->use_slowpath = false; /* Assume fast SGL by default */ + io_req->sge_type = QEDF_IOREQ_FAST_SGE; /* Assume fast SGL by default */ /* Record which cpu this request is associated with */ io_req->cpu = smp_processor_id(); @@ -895,15 +877,24 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) /* Build buffer descriptor list for firmware from sg list */ if (qedf_build_bd_list_from_sg(io_req)) { QEDF_ERR(&(qedf->dbg_ctx), "BD list creation failed.\n"); + /* Release cmd will release io_req, but sc_cmd is assigned */ + io_req->sc_cmd = NULL; kref_put(&io_req->refcount, qedf_release_cmd); return -EAGAIN; } - if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { + if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || + test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "Session not offloaded yet.\n"); + /* Release cmd will release io_req, but sc_cmd is assigned */ + io_req->sc_cmd = NULL; kref_put(&io_req->refcount, qedf_release_cmd); + return -EINVAL; } + /* Record LUN number for later use if we neeed them */ + io_req->lun = (int)sc_cmd->device->lun; + /* Obtain free SQE */ sqe_idx = qedf_get_sqe_idx(fcport); sqe = &fcport->sq[sqe_idx]; @@ -914,6 +905,8 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) if (!task_ctx) { QEDF_WARN(&(qedf->dbg_ctx), "task_ctx is NULL, xid=%d.\n", xid); + /* Release cmd will release io_req, but sc_cmd is assigned */ + io_req->sc_cmd = NULL; kref_put(&io_req->refcount, qedf_release_cmd); return -EINVAL; } @@ -923,6 +916,9 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) /* Ring doorbell */ qedf_ring_doorbell(fcport); + /* Set that command is with the firmware now */ + set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + if (qedf_io_tracing && io_req->sc_cmd) qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_REQ); @@ -941,7 +937,17 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) int rc = 0; int rval; unsigned long flags = 0; - + int num_sgs = 0; + + num_sgs = scsi_sg_count(sc_cmd); + if (scsi_sg_count(sc_cmd) > QEDF_MAX_BDS_PER_CMD) { + QEDF_ERR(&qedf->dbg_ctx, + "Number of SG elements %d exceeds what hardware limitation of %d.\n", + num_sgs, QEDF_MAX_BDS_PER_CMD); + sc_cmd->result = DID_ERROR; + sc_cmd->scsi_done(sc_cmd); + return 0; + } if (test_bit(QEDF_UNLOADING, &qedf->flags) || test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { @@ -981,7 +987,8 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) /* rport and tgt are allocated together, so tgt should be non-NULL */ fcport = (struct qedf_rport *)&rp[1]; - if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { + if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) || + test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { /* * Session is not offloaded yet. Let SCSI-ml retry * the command. @@ -989,12 +996,16 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) rc = SCSI_MLQUEUE_TARGET_BUSY; goto exit_qcmd; } + + atomic_inc(&fcport->ios_to_queue); + if (fcport->retry_delay_timestamp) { if (time_after(jiffies, fcport->retry_delay_timestamp)) { fcport->retry_delay_timestamp = 0; } else { /* If retry_delay timer is active, flow off the ML */ rc = SCSI_MLQUEUE_TARGET_BUSY; + atomic_dec(&fcport->ios_to_queue); goto exit_qcmd; } } @@ -1002,6 +1013,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) io_req = qedf_alloc_cmd(fcport, QEDF_SCSI_CMD); if (!io_req) { rc = SCSI_MLQUEUE_HOST_BUSY; + atomic_dec(&fcport->ios_to_queue); goto exit_qcmd; } @@ -1016,6 +1028,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) rc = SCSI_MLQUEUE_HOST_BUSY; } spin_unlock_irqrestore(&fcport->rport_lock, flags); + atomic_dec(&fcport->ios_to_queue); exit_qcmd: return rc; @@ -1092,7 +1105,7 @@ static void qedf_unmap_sg_list(struct qedf_ctx *qedf, struct qedf_ioreq *io_req) void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, struct qedf_ioreq *io_req) { - u16 xid, rval; + u16 xid; struct e4_fcoe_task_context *task_ctx; struct scsi_cmnd *sc_cmd; struct fcoe_cqe_rsp_info *fcp_rsp; @@ -1106,6 +1119,15 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, if (!cqe) return; + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || + test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || + test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "io_req xid=0x%x already in cleanup or abort processing or already completed.\n", + io_req->xid); + return; + } + xid = io_req->xid; task_ctx = qedf_get_task_mem(&qedf->tasks, xid); sc_cmd = io_req->sc_cmd; @@ -1122,6 +1144,12 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, return; } + if (!sc_cmd->device) { + QEDF_ERR(&qedf->dbg_ctx, + "Device for sc_cmd %p is NULL.\n", sc_cmd); + return; + } + if (!sc_cmd->request) { QEDF_WARN(&(qedf->dbg_ctx), "sc_cmd->request is NULL, " "sc_cmd=%p.\n", sc_cmd); @@ -1136,6 +1164,19 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, fcport = io_req->fcport; + /* + * When flush is active, let the cmds be completed from the cleanup + * context + */ + if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) || + (test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags) && + sc_cmd->device->lun == (u64)fcport->lun_reset_lun)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Dropping good completion xid=0x%x as fcport is flushing", + io_req->xid); + return; + } + qedf_parse_fcp_rsp(io_req, fcp_rsp); qedf_unmap_sg_list(qedf, io_req); @@ -1153,25 +1194,18 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, fw_residual_flag = GET_FIELD(cqe->cqe_info.rsp_info.fw_error_flags, FCOE_CQE_RSP_INFO_FW_UNDERRUN); if (fw_residual_flag) { - QEDF_ERR(&(qedf->dbg_ctx), - "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x " - "fcp_resid=%d fw_residual=0x%x.\n", io_req->xid, - fcp_rsp->rsp_flags.flags, io_req->fcp_resid, - cqe->cqe_info.rsp_info.fw_residual); + QEDF_ERR(&qedf->dbg_ctx, + "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x fcp_resid=%d fw_residual=0x%x lba=%02x%02x%02x%02x.\n", + io_req->xid, fcp_rsp->rsp_flags.flags, + io_req->fcp_resid, + cqe->cqe_info.rsp_info.fw_residual, sc_cmd->cmnd[2], + sc_cmd->cmnd[3], sc_cmd->cmnd[4], sc_cmd->cmnd[5]); if (io_req->cdb_status == 0) sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status; else sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; - /* Abort the command since we did not get all the data */ - init_completion(&io_req->abts_done); - rval = qedf_initiate_abts(io_req, true); - if (rval) { - QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n"); - sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status; - } - /* * Set resid to the whole buffer length so we won't try to resue * any previously data. @@ -1243,6 +1277,12 @@ out: if (qedf_io_tracing) qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_RSP); + /* + * We wait till the end of the function to clear the + * outstanding bit in case we need to send an abort + */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + io_req->sc_cmd = NULL; sc_cmd->SCp.ptr = NULL; sc_cmd->scsi_done(sc_cmd); @@ -1260,6 +1300,19 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, if (!io_req) return; + if (test_and_set_bit(QEDF_CMD_ERR_SCSI_DONE, &io_req->flags)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "io_req:%p scsi_done handling already done\n", + io_req); + return; + } + + /* + * We will be done with this command after this call so clear the + * outstanding bit. + */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + xid = io_req->xid; sc_cmd = io_req->sc_cmd; @@ -1268,12 +1321,50 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, return; } + if (!virt_addr_valid(sc_cmd)) { + QEDF_ERR(&qedf->dbg_ctx, "sc_cmd=%p is not valid.", sc_cmd); + goto bad_scsi_ptr; + } + if (!sc_cmd->SCp.ptr) { QEDF_WARN(&(qedf->dbg_ctx), "SCp.ptr is NULL, returned in " "another context.\n"); return; } + if (!sc_cmd->device) { + QEDF_ERR(&qedf->dbg_ctx, "Device for sc_cmd %p is NULL.\n", + sc_cmd); + goto bad_scsi_ptr; + } + + if (!virt_addr_valid(sc_cmd->device)) { + QEDF_ERR(&qedf->dbg_ctx, + "Device pointer for sc_cmd %p is bad.\n", sc_cmd); + goto bad_scsi_ptr; + } + + if (!sc_cmd->sense_buffer) { + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd->sense_buffer for sc_cmd %p is NULL.\n", + sc_cmd); + goto bad_scsi_ptr; + } + + if (!virt_addr_valid(sc_cmd->sense_buffer)) { + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd->sense_buffer for sc_cmd %p is bad.\n", + sc_cmd); + goto bad_scsi_ptr; + } + + if (!sc_cmd->scsi_done) { + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd->scsi_done for sc_cmd %p is NULL.\n", + sc_cmd); + goto bad_scsi_ptr; + } + qedf_unmap_sg_list(qedf, io_req); sc_cmd->result = result << 16; @@ -1300,6 +1391,15 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, sc_cmd->SCp.ptr = NULL; sc_cmd->scsi_done(sc_cmd); kref_put(&io_req->refcount, qedf_release_cmd); + return; + +bad_scsi_ptr: + /* + * Clear the io_req->sc_cmd backpointer so we don't try to process + * this again + */ + io_req->sc_cmd = NULL; + kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 001 */ } /* @@ -1438,6 +1538,10 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) struct qedf_ctx *qedf; struct qedf_cmd_mgr *cmd_mgr; int i, rc; + unsigned long flags; + int flush_cnt = 0; + int wait_cnt = 100; + int refcount = 0; if (!fcport) return; @@ -1449,18 +1553,102 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) } qedf = fcport->qedf; + + if (!qedf) { + QEDF_ERR(NULL, "qedf is NULL.\n"); + return; + } + + /* Only wait for all commands to be queued in the Upload context */ + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) && + (lun == -1)) { + while (atomic_read(&fcport->ios_to_queue)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Waiting for %d I/Os to be queued\n", + atomic_read(&fcport->ios_to_queue)); + if (wait_cnt == 0) { + QEDF_ERR(NULL, + "%d IOs request could not be queued\n", + atomic_read(&fcport->ios_to_queue)); + } + msleep(20); + wait_cnt--; + } + } + cmd_mgr = qedf->cmd_mgr; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Flush active i/o's.\n"); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Flush active i/o's num=0x%x fcport=0x%p port_id=0x%06x scsi_id=%d.\n", + atomic_read(&fcport->num_active_ios), fcport, + fcport->rdata->ids.port_id, fcport->rport->scsi_target_id); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Locking flush mutex.\n"); + + mutex_lock(&qedf->flush_mutex); + if (lun == -1) { + set_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags); + } else { + set_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags); + fcport->lun_reset_lun = lun; + } for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { io_req = &cmd_mgr->cmds[i]; if (!io_req) continue; + if (!io_req->fcport) + continue; + + spin_lock_irqsave(&cmd_mgr->lock, flags); + + if (io_req->alloc) { + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) { + if (io_req->cmd_type == QEDF_SCSI_CMD) + QEDF_ERR(&qedf->dbg_ctx, + "Allocated but not queued, xid=0x%x\n", + io_req->xid); + } + spin_unlock_irqrestore(&cmd_mgr->lock, flags); + } else { + spin_unlock_irqrestore(&cmd_mgr->lock, flags); + continue; + } + if (io_req->fcport != fcport) continue; - if (io_req->cmd_type == QEDF_ELS) { + + /* In case of ABTS, CMD_OUTSTANDING is cleared on ABTS response, + * but RRQ is still pending. + * Workaround: Within qedf_send_rrq, we check if the fcport is + * NULL, and we drop the ref on the io_req to clean it up. + */ + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) { + refcount = kref_read(&io_req->refcount); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Not outstanding, xid=0x%x, cmd_type=%d refcount=%d.\n", + io_req->xid, io_req->cmd_type, refcount); + /* If RRQ work has been queue, try to cancel it and + * free the io_req + */ + if (atomic_read(&io_req->state) == + QEDFC_CMD_ST_RRQ_WAIT) { + if (cancel_delayed_work_sync + (&io_req->rrq_work)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Putting reference for pending RRQ work xid=0x%x.\n", + io_req->xid); + /* ID: 003 */ + kref_put(&io_req->refcount, + qedf_release_cmd); + } + } + continue; + } + + /* Only consider flushing ELS during target reset */ + if (io_req->cmd_type == QEDF_ELS && + lun == -1) { rc = kref_get_unless_zero(&io_req->refcount); if (!rc) { QEDF_ERR(&(qedf->dbg_ctx), @@ -1468,6 +1656,7 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) io_req, io_req->xid); continue; } + flush_cnt++; qedf_flush_els_req(qedf, io_req); /* * Release the kref and go back to the top of the @@ -1477,6 +1666,7 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) } if (io_req->cmd_type == QEDF_ABTS) { + /* ID: 004 */ rc = kref_get_unless_zero(&io_req->refcount); if (!rc) { QEDF_ERR(&(qedf->dbg_ctx), @@ -1484,28 +1674,50 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) io_req, io_req->xid); continue; } + if (lun != -1 && io_req->lun != lun) + goto free_cmd; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Flushing abort xid=0x%x.\n", io_req->xid); - clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); - - if (io_req->sc_cmd) { - if (io_req->return_scsi_cmd_on_abts) - qedf_scsi_done(qedf, io_req, DID_ERROR); + if (cancel_delayed_work_sync(&io_req->rrq_work)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Putting ref for cancelled RRQ work xid=0x%x.\n", + io_req->xid); + kref_put(&io_req->refcount, qedf_release_cmd); } - /* Notify eh_abort handler that ABTS is complete */ - complete(&io_req->abts_done); - kref_put(&io_req->refcount, qedf_release_cmd); - + if (cancel_delayed_work_sync(&io_req->timeout_work)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Putting ref for cancelled tmo work xid=0x%x.\n", + io_req->xid); + qedf_initiate_cleanup(io_req, true); + /* Notify eh_abort handler that ABTS is + * complete + */ + complete(&io_req->abts_done); + clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); + /* ID: 002 */ + kref_put(&io_req->refcount, qedf_release_cmd); + } + flush_cnt++; goto free_cmd; } if (!io_req->sc_cmd) continue; - if (lun > 0) { - if (io_req->sc_cmd->device->lun != - (u64)lun) + if (!io_req->sc_cmd->device) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Device backpointer NULL for sc_cmd=%p.\n", + io_req->sc_cmd); + /* Put reference for non-existent scsi_cmnd */ + io_req->sc_cmd = NULL; + qedf_initiate_cleanup(io_req, false); + kref_put(&io_req->refcount, qedf_release_cmd); + continue; + } + if (lun > -1) { + if (io_req->lun != lun) continue; } @@ -1519,15 +1731,65 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) "io_req=0x%p xid=0x%x\n", io_req, io_req->xid); continue; } + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Cleanup xid=0x%x.\n", io_req->xid); + flush_cnt++; /* Cleanup task and return I/O mid-layer */ qedf_initiate_cleanup(io_req, true); free_cmd: - kref_put(&io_req->refcount, qedf_release_cmd); + kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 004 */ + } + + wait_cnt = 60; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Flushed 0x%x I/Os, active=0x%x.\n", + flush_cnt, atomic_read(&fcport->num_active_ios)); + /* Only wait for all commands to complete in the Upload context */ + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) && + (lun == -1)) { + while (atomic_read(&fcport->num_active_ios)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Flushed 0x%x I/Os, active=0x%x cnt=%d.\n", + flush_cnt, + atomic_read(&fcport->num_active_ios), + wait_cnt); + if (wait_cnt == 0) { + QEDF_ERR(&qedf->dbg_ctx, + "Flushed %d I/Os, active=%d.\n", + flush_cnt, + atomic_read(&fcport->num_active_ios)); + for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) { + io_req = &cmd_mgr->cmds[i]; + if (io_req->fcport && + io_req->fcport == fcport) { + refcount = + kref_read(&io_req->refcount); + set_bit(QEDF_CMD_DIRTY, + &io_req->flags); + QEDF_ERR(&qedf->dbg_ctx, + "Outstanding io_req =%p xid=0x%x flags=0x%lx, sc_cmd=%p refcount=%d cmd_type=%d.\n", + io_req, io_req->xid, + io_req->flags, + io_req->sc_cmd, + refcount, + io_req->cmd_type); + } + } + WARN_ON(1); + break; + } + msleep(500); + wait_cnt--; + } } + + clear_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags); + clear_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Unlocking flush mutex.\n"); + mutex_unlock(&qedf->flush_mutex); } /* @@ -1546,52 +1808,60 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; + int refcount = 0; /* Sanity check qedf_rport before dereferencing any pointers */ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(NULL, "tgt not offloaded\n"); rc = 1; - goto abts_err; + goto out; } + qedf = fcport->qedf; rdata = fcport->rdata; + + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_ERR(&qedf->dbg_ctx, "stale rport\n"); + rc = 1; + goto out; + } + r_a_tov = rdata->r_a_tov; - qedf = fcport->qedf; lport = qedf->lport; if (lport->state != LPORT_ST_READY || !(lport->link_up)) { QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n"); rc = 1; - goto abts_err; + goto drop_rdata_kref; } if (atomic_read(&qedf->link_down_tmo_valid) > 0) { QEDF_ERR(&(qedf->dbg_ctx), "link_down_tmo active.\n"); rc = 1; - goto abts_err; + goto drop_rdata_kref; } /* Ensure room on SQ */ if (!atomic_read(&fcport->free_sqes)) { QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); rc = 1; - goto abts_err; + goto drop_rdata_kref; } if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&qedf->dbg_ctx, "fcport is uploading.\n"); rc = 1; - goto out; + goto drop_rdata_kref; } if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { - QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in " - "cleanup or abort processing or already " - "completed.\n", io_req->xid); + QEDF_ERR(&qedf->dbg_ctx, + "io_req xid=0x%x sc_cmd=%p already in cleanup or abort processing or already completed.\n", + io_req->xid, io_req->sc_cmd); rc = 1; - goto out; + goto drop_rdata_kref; } kref_get(&io_req->refcount); @@ -1600,18 +1870,17 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) qedf->control_requests++; qedf->packet_aborts++; - /* Set the return CPU to be the same as the request one */ - io_req->cpu = smp_processor_id(); - /* Set the command type to abort */ io_req->cmd_type = QEDF_ABTS; io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; set_bit(QEDF_CMD_IN_ABORT, &io_req->flags); - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "ABTS io_req xid = " - "0x%x\n", xid); + refcount = kref_read(&io_req->refcount); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "ABTS io_req xid = 0x%x refcount=%d\n", + xid, refcount); - qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT * HZ); + qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT); spin_lock_irqsave(&fcport->rport_lock, flags); @@ -1625,13 +1894,8 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) spin_unlock_irqrestore(&fcport->rport_lock, flags); - return rc; -abts_err: - /* - * If the ABTS task fails to queue then we need to cleanup the - * task at the firmware. - */ - qedf_initiate_cleanup(io_req, return_scsi_cmd_on_abts); +drop_rdata_kref: + kref_put(&rdata->kref, fc_rport_destroy); out: return rc; } @@ -1641,27 +1905,62 @@ void qedf_process_abts_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, { uint32_t r_ctl; uint16_t xid; + int rc; + struct qedf_rport *fcport = io_req->fcport; QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "Entered with xid = " "0x%x cmd_type = %d\n", io_req->xid, io_req->cmd_type); - cancel_delayed_work(&io_req->timeout_work); - xid = io_req->xid; r_ctl = cqe->cqe_info.abts_info.r_ctl; + /* This was added at a point when we were scheduling abts_compl & + * cleanup_compl on different CPUs and there was a possibility of + * the io_req to be freed from the other context before we got here. + */ + if (!fcport) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Dropping ABTS completion xid=0x%x as fcport is NULL", + io_req->xid); + return; + } + + /* + * When flush is active, let the cmds be completed from the cleanup + * context + */ + if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) || + test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Dropping ABTS completion xid=0x%x as fcport is flushing", + io_req->xid); + return; + } + + if (!cancel_delayed_work(&io_req->timeout_work)) { + QEDF_ERR(&qedf->dbg_ctx, + "Wasn't able to cancel abts timeout work.\n"); + } + switch (r_ctl) { case FC_RCTL_BA_ACC: QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "ABTS response - ACC Send RRQ after R_A_TOV\n"); io_req->event = QEDF_IOREQ_EV_ABORT_SUCCESS; + rc = kref_get_unless_zero(&io_req->refcount); /* ID: 003 */ + if (!rc) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "kref is already zero so ABTS was already completed or flushed xid=0x%x.\n", + io_req->xid); + return; + } /* * Dont release this cmd yet. It will be relesed * after we get RRQ response */ - kref_get(&io_req->refcount); queue_delayed_work(qedf->dpc_wq, &io_req->rrq_work, msecs_to_jiffies(qedf->lport->r_a_tov)); + atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_WAIT); break; /* For error cases let the cleanup return the command */ case FC_RCTL_BA_RJT: @@ -1803,6 +2102,7 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; + int refcount = 0; fcport = io_req->fcport; if (!fcport) { @@ -1824,36 +2124,45 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, } if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || - test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) { + test_and_set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in " "cleanup processing or already completed.\n", io_req->xid); return SUCCESS; } + set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); /* Ensure room on SQ */ if (!atomic_read(&fcport->free_sqes)) { QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); + /* Need to make sure we clear the flag since it was set */ + clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); return FAILED; } + if (io_req->cmd_type == QEDF_CLEANUP) { + QEDF_ERR(&qedf->dbg_ctx, + "io_req=0x%x is already a cleanup command cmd_type=%d.\n", + io_req->xid, io_req->cmd_type); + clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); + return SUCCESS; + } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Entered xid=0x%x\n", - io_req->xid); + refcount = kref_read(&io_req->refcount); + + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Entered xid=0x%x sc_cmd=%p cmd_type=%d flags=0x%lx refcount=%d fcport=%p port_id=0x%06x\n", + io_req->xid, io_req->sc_cmd, io_req->cmd_type, io_req->flags, + refcount, fcport, fcport->rdata->ids.port_id); /* Cleanup cmds re-use the same TID as the original I/O */ xid = io_req->xid; io_req->cmd_type = QEDF_CLEANUP; io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; - /* Set the return CPU to be the same as the request one */ - io_req->cpu = smp_processor_id(); - - set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); - task = qedf_get_task_mem(&qedf->tasks, xid); - init_completion(&io_req->tm_done); + init_completion(&io_req->cleanup_done); spin_lock_irqsave(&fcport->rport_lock, flags); @@ -1867,8 +2176,8 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, spin_unlock_irqrestore(&fcport->rport_lock, flags); - tmo = wait_for_completion_timeout(&io_req->tm_done, - QEDF_CLEANUP_TIMEOUT * HZ); + tmo = wait_for_completion_timeout(&io_req->cleanup_done, + QEDF_CLEANUP_TIMEOUT * HZ); if (!tmo) { rc = FAILED; @@ -1881,6 +2190,16 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, qedf_drain_request(qedf); } + /* If it TASK MGMT handle it, reference will be decreased + * in qedf_execute_tmf + */ + if (io_req->tm_flags == FCP_TMF_LUN_RESET || + io_req->tm_flags == FCP_TMF_TGT_RESET) { + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + io_req->sc_cmd = NULL; + complete(&io_req->tm_done); + } + if (io_req->sc_cmd) { if (io_req->return_scsi_cmd_on_abts) qedf_scsi_done(qedf, io_req, DID_ERROR); @@ -1903,7 +2222,7 @@ void qedf_process_cleanup_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags); /* Complete so we can finish cleaning up the I/O */ - complete(&io_req->tm_done); + complete(&io_req->cleanup_done); } static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, @@ -1916,6 +2235,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, int rc = 0; uint16_t xid; int tmo = 0; + int lun = 0; unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; @@ -1925,20 +2245,18 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, return FAILED; } + lun = (int)sc_cmd->device->lun; if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n"); rc = FAILED; - return FAILED; + goto no_flush; } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "portid = 0x%x " - "tm_flags = %d\n", fcport->rdata->ids.port_id, tm_flags); - io_req = qedf_alloc_cmd(fcport, QEDF_TASK_MGMT_CMD); if (!io_req) { QEDF_ERR(&(qedf->dbg_ctx), "Failed TMF"); rc = -EAGAIN; - goto reset_tmf_err; + goto no_flush; } if (tm_flags == FCP_TMF_LUN_RESET) @@ -1951,7 +2269,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, io_req->fcport = fcport; io_req->cmd_type = QEDF_TASK_MGMT_CMD; - /* Set the return CPU to be the same as the request one */ + /* Record which cpu this request is associated with */ io_req->cpu = smp_processor_id(); /* Set TM flags */ @@ -1960,7 +2278,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, io_req->tm_flags = tm_flags; /* Default is to return a SCSI command when an error occurs */ - io_req->return_scsi_cmd_on_abts = true; + io_req->return_scsi_cmd_on_abts = false; /* Obtain exchange id */ xid = io_req->xid; @@ -1984,12 +2302,16 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, spin_unlock_irqrestore(&fcport->rport_lock, flags); + set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); tmo = wait_for_completion_timeout(&io_req->tm_done, QEDF_TM_TIMEOUT * HZ); if (!tmo) { rc = FAILED; QEDF_ERR(&(qedf->dbg_ctx), "wait for tm_cmpl timeout!\n"); + /* Clear outstanding bit since command timed out */ + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + io_req->sc_cmd = NULL; } else { /* Check TMF response code */ if (io_req->fcp_rsp_code == 0) @@ -1997,14 +2319,25 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, else rc = FAILED; } + /* + * Double check that fcport has not gone into an uploading state before + * executing the command flush for the LUN/target. + */ + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "fcport is uploading, not executing flush.\n"); + goto no_flush; + } + /* We do not need this io_req any more */ + kref_put(&io_req->refcount, qedf_release_cmd); + if (tm_flags == FCP_TMF_LUN_RESET) - qedf_flush_active_ios(fcport, (int)sc_cmd->device->lun); + qedf_flush_active_ios(fcport, lun); else qedf_flush_active_ios(fcport, -1); - kref_put(&io_req->refcount, qedf_release_cmd); - +no_flush: if (rc != SUCCESS) { QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command failed...\n"); rc = FAILED; @@ -2012,7 +2345,6 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command success...\n"); rc = SUCCESS; } -reset_tmf_err: return rc; } @@ -2022,26 +2354,65 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) struct fc_rport_libfc_priv *rp = rport->dd_data; struct qedf_rport *fcport = (struct qedf_rport *)&rp[1]; struct qedf_ctx *qedf; - struct fc_lport *lport; + struct fc_lport *lport = shost_priv(sc_cmd->device->host); int rc = SUCCESS; int rval; + struct qedf_ioreq *io_req = NULL; + int ref_cnt = 0; + struct fc_rport_priv *rdata = fcport->rdata; - rval = fc_remote_port_chkready(rport); + QEDF_ERR(NULL, + "tm_flags 0x%x sc_cmd %p op = 0x%02x target_id = 0x%x lun=%d\n", + tm_flags, sc_cmd, sc_cmd->cmnd[0], rport->scsi_target_id, + (int)sc_cmd->device->lun); + + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_ERR(NULL, "stale rport\n"); + return FAILED; + } + + QEDF_ERR(NULL, "portid=%06x tm_flags =%s\n", rdata->ids.port_id, + (tm_flags == FCP_TMF_TGT_RESET) ? "TARGET RESET" : + "LUN RESET"); + + if (sc_cmd->SCp.ptr) { + io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr; + ref_cnt = kref_read(&io_req->refcount); + QEDF_ERR(NULL, + "orig io_req = %p xid = 0x%x ref_cnt = %d.\n", + io_req, io_req->xid, ref_cnt); + } + rval = fc_remote_port_chkready(rport); if (rval) { QEDF_ERR(NULL, "device_reset rport not ready\n"); rc = FAILED; goto tmf_err; } - if (fcport == NULL) { + rc = fc_block_scsi_eh(sc_cmd); + if (rc) + goto tmf_err; + + if (!fcport) { QEDF_ERR(NULL, "device_reset: rport is NULL\n"); rc = FAILED; goto tmf_err; } qedf = fcport->qedf; - lport = qedf->lport; + + if (!qedf) { + QEDF_ERR(NULL, "qedf is NULL.\n"); + rc = FAILED; + goto tmf_err; + } + + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + QEDF_ERR(&qedf->dbg_ctx, "Connection is getting uploaded.\n"); + rc = SUCCESS; + goto tmf_err; + } if (test_bit(QEDF_UNLOADING, &qedf->flags) || test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { @@ -2055,9 +2426,22 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) goto tmf_err; } + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + if (!fcport->rdata) + QEDF_ERR(&qedf->dbg_ctx, "fcport %p is uploading.\n", + fcport); + else + QEDF_ERR(&qedf->dbg_ctx, + "fcport %p port_id=%06x is uploading.\n", + fcport, fcport->rdata->ids.port_id); + rc = FAILED; + goto tmf_err; + } + rc = qedf_execute_tmf(fcport, sc_cmd, tm_flags); tmf_err: + kref_put(&rdata->kref, fc_rport_destroy); return rc; } @@ -2066,6 +2450,8 @@ void qedf_process_tmf_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, { struct fcoe_cqe_rsp_info *fcp_rsp; + clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags); + fcp_rsp = &cqe->cqe_info.rsp_info; qedf_parse_fcp_rsp(io_req, fcp_rsp); diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 9f9431a4cc0e..a42babde036d 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/init.h> #include <linux/kernel.h> @@ -124,21 +121,24 @@ static bool qedf_initiate_fipvlan_req(struct qedf_ctx *qedf) { int rc; - if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) { - QEDF_ERR(&(qedf->dbg_ctx), "Link not up.\n"); - return false; - } - while (qedf->fipvlan_retries--) { + /* This is to catch if link goes down during fipvlan retries */ + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { + QEDF_ERR(&qedf->dbg_ctx, "Link not up.\n"); + return false; + } + if (qedf->vlan_id > 0) return true; + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Retry %d.\n", qedf->fipvlan_retries); init_completion(&qedf->fipvlan_compl); qedf_fcoe_send_vlan_req(qedf); rc = wait_for_completion_timeout(&qedf->fipvlan_compl, 1 * HZ); - if (rc > 0) { + if (rc > 0 && + (atomic_read(&qedf->link_state) == QEDF_LINK_UP)) { fcoe_ctlr_link_up(&qedf->ctlr); return true; } @@ -153,12 +153,19 @@ static void qedf_handle_link_update(struct work_struct *work) container_of(work, struct qedf_ctx, link_update.work); int rc; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Entered.\n"); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Entered. link_state=%d.\n", + atomic_read(&qedf->link_state)); if (atomic_read(&qedf->link_state) == QEDF_LINK_UP) { rc = qedf_initiate_fipvlan_req(qedf); if (rc) return; + + if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) { + qedf->vlan_id = 0; + return; + } + /* * If we get here then we never received a repsonse to our * fip vlan request so set the vlan_id to the default and @@ -185,7 +192,9 @@ static void qedf_handle_link_update(struct work_struct *work) QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Calling fcoe_ctlr_link_down().\n"); fcoe_ctlr_link_down(&qedf->ctlr); - qedf_wait_for_upload(qedf); + if (qedf_wait_for_upload(qedf) == false) + QEDF_ERR(&qedf->dbg_ctx, + "Could not upload all sessions.\n"); /* Reset the number of FIP VLAN retries */ qedf->fipvlan_retries = qedf_fipvlan_retries; } @@ -615,50 +624,113 @@ static struct scsi_transport_template *qedf_fc_vport_transport_template; static int qedf_eh_abort(struct scsi_cmnd *sc_cmd) { 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; struct fc_lport *lport; struct qedf_ctx *qedf; struct qedf_ioreq *io_req; + struct fc_rport_libfc_priv *rp = rport->dd_data; + struct fc_rport_priv *rdata; + struct qedf_rport *fcport = NULL; int rc = FAILED; + int wait_count = 100; + int refcount = 0; int rval; - - if (fc_remote_port_chkready(rport)) { - QEDF_ERR(NULL, "rport not ready\n"); - goto out; - } + int got_ref = 0; lport = shost_priv(sc_cmd->device->host); qedf = (struct qedf_ctx *)lport_priv(lport); - if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) { - QEDF_ERR(&(qedf->dbg_ctx), "link not ready.\n"); + /* rport and tgt are allocated together, so tgt should be non-NULL */ + fcport = (struct qedf_rport *)&rp[1]; + rdata = fcport->rdata; + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_ERR(&qedf->dbg_ctx, "stale rport, sc_cmd=%p\n", sc_cmd); + rc = 1; goto out; } - fcport = (struct qedf_rport *)&rp[1]; io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr; if (!io_req) { - QEDF_ERR(&(qedf->dbg_ctx), "io_req is NULL.\n"); + QEDF_ERR(&qedf->dbg_ctx, + "sc_cmd not queued with lld, sc_cmd=%p op=0x%02x, port_id=%06x\n", + sc_cmd, sc_cmd->cmnd[0], + rdata->ids.port_id); rc = SUCCESS; - goto out; + goto drop_rdata_kref; } - QEDF_ERR(&(qedf->dbg_ctx), "Aborting io_req sc_cmd=%p xid=0x%x " - "fp_idx=%d.\n", sc_cmd, io_req->xid, io_req->fp_idx); + rval = kref_get_unless_zero(&io_req->refcount); /* ID: 005 */ + if (rval) + got_ref = 1; + + /* If we got a valid io_req, confirm it belongs to this sc_cmd. */ + if (!rval || io_req->sc_cmd != sc_cmd) { + QEDF_ERR(&qedf->dbg_ctx, + "Freed/Incorrect io_req, io_req->sc_cmd=%p, sc_cmd=%p, port_id=%06x, bailing out.\n", + io_req->sc_cmd, sc_cmd, rdata->ids.port_id); + + goto drop_rdata_kref; + } + + if (fc_remote_port_chkready(rport)) { + refcount = kref_read(&io_req->refcount); + QEDF_ERR(&qedf->dbg_ctx, + "rport not ready, io_req=%p, xid=0x%x sc_cmd=%p op=0x%02x, refcount=%d, port_id=%06x\n", + io_req, io_req->xid, sc_cmd, sc_cmd->cmnd[0], + refcount, rdata->ids.port_id); + + goto drop_rdata_kref; + } + + rc = fc_block_scsi_eh(sc_cmd); + if (rc) + goto drop_rdata_kref; + + if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "Connection uploading, xid=0x%x., port_id=%06x\n", + io_req->xid, rdata->ids.port_id); + while (io_req->sc_cmd && (wait_count != 0)) { + msleep(100); + wait_count--; + } + if (wait_count) { + QEDF_ERR(&qedf->dbg_ctx, "ABTS succeeded\n"); + rc = SUCCESS; + } else { + QEDF_ERR(&qedf->dbg_ctx, "ABTS failed\n"); + rc = FAILED; + } + goto drop_rdata_kref; + } + + if (lport->state != LPORT_ST_READY || !(lport->link_up)) { + QEDF_ERR(&qedf->dbg_ctx, "link not ready.\n"); + goto drop_rdata_kref; + } + + QEDF_ERR(&qedf->dbg_ctx, + "Aborting io_req=%p sc_cmd=%p xid=0x%x fp_idx=%d, port_id=%06x.\n", + io_req, sc_cmd, io_req->xid, io_req->fp_idx, + rdata->ids.port_id); if (qedf->stop_io_on_error) { qedf_stop_all_io(qedf); rc = SUCCESS; - goto out; + goto drop_rdata_kref; } init_completion(&io_req->abts_done); rval = qedf_initiate_abts(io_req, true); if (rval) { QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n"); - goto out; + /* + * If we fail to queue the ABTS then return this command to + * the SCSI layer as it will own and free the xid + */ + rc = SUCCESS; + qedf_scsi_done(qedf, io_req, DID_ERROR); + goto drop_rdata_kref; } wait_for_completion(&io_req->abts_done); @@ -684,38 +756,68 @@ static int qedf_eh_abort(struct scsi_cmnd *sc_cmd) QEDF_ERR(&(qedf->dbg_ctx), "ABTS failed, xid=0x%x.\n", io_req->xid); +drop_rdata_kref: + kref_put(&rdata->kref, fc_rport_destroy); out: + if (got_ref) + kref_put(&io_req->refcount, qedf_release_cmd); return rc; } static int qedf_eh_target_reset(struct scsi_cmnd *sc_cmd) { - QEDF_ERR(NULL, "TARGET RESET Issued..."); + QEDF_ERR(NULL, "%d:0:%d:%lld: TARGET RESET Issued...", + sc_cmd->device->host->host_no, sc_cmd->device->id, + sc_cmd->device->lun); return qedf_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET); } static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd) { - QEDF_ERR(NULL, "LUN RESET Issued...\n"); + QEDF_ERR(NULL, "%d:0:%d:%lld: LUN RESET Issued... ", + sc_cmd->device->host->host_no, sc_cmd->device->id, + sc_cmd->device->lun); return qedf_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } -void qedf_wait_for_upload(struct qedf_ctx *qedf) +bool qedf_wait_for_upload(struct qedf_ctx *qedf) { - while (1) { + struct qedf_rport *fcport = NULL; + int wait_cnt = 120; + + while (wait_cnt--) { if (atomic_read(&qedf->num_offloads)) - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, - "Waiting for all uploads to complete.\n"); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Waiting for all uploads to complete num_offloads = 0x%x.\n", + atomic_read(&qedf->num_offloads)); else - break; + return true; msleep(500); } + + rcu_read_lock(); + list_for_each_entry_rcu(fcport, &qedf->fcports, peers) { + if (fcport && test_bit(QEDF_RPORT_SESSION_READY, + &fcport->flags)) { + if (fcport->rdata) + QEDF_ERR(&qedf->dbg_ctx, + "Waiting for fcport %p portid=%06x.\n", + fcport, fcport->rdata->ids.port_id); + } else { + QEDF_ERR(&qedf->dbg_ctx, + "Waiting for fcport %p.\n", fcport); + } + } + rcu_read_unlock(); + return false; + } /* Performs soft reset of qedf_ctx by simulating a link down/up */ -static void qedf_ctx_soft_reset(struct fc_lport *lport) +void qedf_ctx_soft_reset(struct fc_lport *lport) { struct qedf_ctx *qedf; + struct qed_link_output if_link; if (lport->vport) { QEDF_ERR(NULL, "Cannot issue host reset on NPIV port.\n"); @@ -726,11 +828,32 @@ static void qedf_ctx_soft_reset(struct fc_lport *lport) /* For host reset, essentially do a soft link up/down */ atomic_set(&qedf->link_state, QEDF_LINK_DOWN); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Queuing link down work.\n"); queue_delayed_work(qedf->link_update_wq, &qedf->link_update, 0); - qedf_wait_for_upload(qedf); + + if (qedf_wait_for_upload(qedf) == false) { + QEDF_ERR(&qedf->dbg_ctx, "Could not upload all sessions.\n"); + WARN_ON(atomic_read(&qedf->num_offloads)); + } + + /* Before setting link up query physical link state */ + qed_ops->common->get_link(qedf->cdev, &if_link); + /* Bail if the physical link is not up */ + if (!if_link.link_up) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Physical link is not up.\n"); + return; + } + /* Flush and wait to make sure link down is processed */ + flush_delayed_work(&qedf->link_update); + msleep(500); + atomic_set(&qedf->link_state, QEDF_LINK_UP); qedf->vlan_id = 0; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Queue link up work.\n"); queue_delayed_work(qedf->link_update_wq, &qedf->link_update, 0); } @@ -740,22 +863,6 @@ static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd) { struct fc_lport *lport; struct qedf_ctx *qedf; - 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 = (struct qedf_rport *)&rp[1]; - int rval; - - rval = fc_remote_port_chkready(rport); - - if (rval) { - QEDF_ERR(NULL, "device_reset rport not ready\n"); - return FAILED; - } - - if (fcport == NULL) { - QEDF_ERR(NULL, "device_reset: rport is NULL\n"); - return FAILED; - } lport = shost_priv(sc_cmd->device->host); qedf = lport_priv(lport); @@ -907,8 +1014,10 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp) "Dropping FCoE frame to %06x.\n", ntoh24(fh->fh_d_id)); kfree_skb(skb); rdata = fc_rport_lookup(lport, ntoh24(fh->fh_d_id)); - if (rdata) + if (rdata) { rdata->retries = lport->max_rport_retry_count; + kref_put(&rdata->kref, fc_rport_destroy); + } return -EINVAL; } /* End NPIV filtering */ @@ -1031,7 +1140,12 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp) if (qedf_dump_frames) print_hex_dump(KERN_WARNING, "fcoe: ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, false); - qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); + kfree_skb(skb); + return rc; + } return 0; } @@ -1224,6 +1338,8 @@ static void qedf_upload_connection(struct qedf_ctx *qedf, static void qedf_cleanup_fcport(struct qedf_ctx *qedf, struct qedf_rport *fcport) { + struct fc_rport_priv *rdata = fcport->rdata; + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Cleaning up portid=%06x.\n", fcport->rdata->ids.port_id); @@ -1235,6 +1351,7 @@ static void qedf_cleanup_fcport(struct qedf_ctx *qedf, qedf_free_sq(qedf, fcport); fcport->rdata = NULL; fcport->qedf = NULL; + kref_put(&rdata->kref, fc_rport_destroy); } /** @@ -1310,6 +1427,8 @@ static void qedf_rport_event_handler(struct fc_lport *lport, break; } + /* Initial reference held on entry, so this can't fail */ + kref_get(&rdata->kref); fcport->rdata = rdata; fcport->rport = rport; @@ -1369,11 +1488,15 @@ static void qedf_rport_event_handler(struct fc_lport *lport, */ fcport = (struct qedf_rport *)&rp[1]; + spin_lock_irqsave(&fcport->rport_lock, flags); /* Only free this fcport if it is offloaded already */ - if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { - set_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags); + if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) && + !test_bit(QEDF_RPORT_UPLOADING_CONNECTION, + &fcport->flags)) { + set_bit(QEDF_RPORT_UPLOADING_CONNECTION, + &fcport->flags); + spin_unlock_irqrestore(&fcport->rport_lock, flags); qedf_cleanup_fcport(qedf, fcport); - /* * Remove fcport to list of qedf_ctx list of offloaded * ports @@ -1385,8 +1508,9 @@ static void qedf_rport_event_handler(struct fc_lport *lport, clear_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags); atomic_dec(&qedf->num_offloads); + } else { + spin_unlock_irqrestore(&fcport->rport_lock, flags); } - break; case RPORT_EV_NONE: @@ -1498,11 +1622,15 @@ static int qedf_lport_setup(struct qedf_ctx *qedf) fc_set_wwnn(lport, qedf->wwnn); fc_set_wwpn(lport, qedf->wwpn); - fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0); + if (fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0)) { + QEDF_ERR(&qedf->dbg_ctx, + "fcoe_libfc_config failed.\n"); + return -ENOMEM; + } /* Allocate the exchange manager */ - fc_exch_mgr_alloc(lport, FC_CLASS_3, qedf->max_scsi_xid + 1, - qedf->max_els_xid, NULL); + fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_PARAMS_NUM_TASKS, + 0xfffe, NULL); if (fc_lport_init_stats(lport)) return -ENOMEM; @@ -1625,14 +1753,15 @@ static int qedf_vport_create(struct fc_vport *vport, bool disabled) vport_qedf->wwpn = vn_port->wwpn; vn_port->host->transportt = qedf_fc_vport_transport_template; - vn_port->host->can_queue = QEDF_MAX_ELS_XID; + vn_port->host->can_queue = FCOE_PARAMS_NUM_TASKS; vn_port->host->max_lun = qedf_max_lun; vn_port->host->sg_tablesize = QEDF_MAX_BDS_PER_CMD; vn_port->host->max_cmd_len = QEDF_MAX_CDB_LEN; rc = scsi_add_host(vn_port->host, &vport->dev); if (rc) { - QEDF_WARN(&(base_qedf->dbg_ctx), "Error adding Scsi_Host.\n"); + QEDF_WARN(&base_qedf->dbg_ctx, + "Error adding Scsi_Host rc=0x%x.\n", rc); goto err2; } @@ -2086,16 +2215,21 @@ static void qedf_simd_int_handler(void *cookie) static void qedf_sync_free_irqs(struct qedf_ctx *qedf) { int i; + u16 vector_idx = 0; + u32 vector; if (qedf->int_info.msix_cnt) { for (i = 0; i < qedf->int_info.used_cnt; i++) { - synchronize_irq(qedf->int_info.msix[i].vector); - irq_set_affinity_hint(qedf->int_info.msix[i].vector, - NULL); - irq_set_affinity_notifier(qedf->int_info.msix[i].vector, - NULL); - free_irq(qedf->int_info.msix[i].vector, - &qedf->fp_array[i]); + vector_idx = i * qedf->dev_info.common.num_hwfns + + qed_ops->common->get_affin_hwfn_idx(qedf->cdev); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Freeing IRQ #%d vector_idx=%d.\n", + i, vector_idx); + vector = qedf->int_info.msix[vector_idx].vector; + synchronize_irq(vector); + irq_set_affinity_hint(vector, NULL); + irq_set_affinity_notifier(vector, NULL); + free_irq(vector, &qedf->fp_array[i]); } } else qed_ops->common->simd_handler_clean(qedf->cdev, @@ -2108,11 +2242,19 @@ static void qedf_sync_free_irqs(struct qedf_ctx *qedf) static int qedf_request_msix_irq(struct qedf_ctx *qedf) { int i, rc, cpu; + u16 vector_idx = 0; + u32 vector; cpu = cpumask_first(cpu_online_mask); for (i = 0; i < qedf->num_queues; i++) { - rc = request_irq(qedf->int_info.msix[i].vector, - qedf_msix_handler, 0, "qedf", &qedf->fp_array[i]); + vector_idx = i * qedf->dev_info.common.num_hwfns + + qed_ops->common->get_affin_hwfn_idx(qedf->cdev); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Requesting IRQ #%d vector_idx=%d.\n", + i, vector_idx); + vector = qedf->int_info.msix[vector_idx].vector; + rc = request_irq(vector, qedf_msix_handler, 0, "qedf", + &qedf->fp_array[i]); if (rc) { QEDF_WARN(&(qedf->dbg_ctx), "request_irq failed.\n"); @@ -2121,8 +2263,7 @@ static int qedf_request_msix_irq(struct qedf_ctx *qedf) } qedf->int_info.used_cnt++; - rc = irq_set_affinity_hint(qedf->int_info.msix[i].vector, - get_cpu_mask(cpu)); + rc = irq_set_affinity_hint(vector, get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } @@ -2155,7 +2296,8 @@ static int qedf_setup_int(struct qedf_ctx *qedf) QEDF_SIMD_HANDLER_NUM, qedf_simd_int_handler); qedf->int_info.used_cnt = 1; - QEDF_ERR(&qedf->dbg_ctx, "Only MSI-X supported. Failing probe.\n"); + QEDF_ERR(&qedf->dbg_ctx, + "Cannot load driver due to a lack of MSI-X vectors.\n"); return -EINVAL; } @@ -2356,6 +2498,13 @@ static int qedf_ll2_rx(void *cookie, struct sk_buff *skb, struct qedf_ctx *qedf = (struct qedf_ctx *)cookie; struct qedf_skb_work *skb_work; + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "Dropping frame as link state is down.\n"); + kfree_skb(skb); + return 0; + } + skb_work = kzalloc(sizeof(struct qedf_skb_work), GFP_ATOMIC); if (!skb_work) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate skb_work so " @@ -2990,6 +3139,8 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) goto err0; } + fc_disc_init(lport); + /* Initialize qedf_ctx */ qedf = lport_priv(lport); qedf->lport = lport; @@ -3005,6 +3156,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) pci_set_drvdata(pdev, qedf); init_completion(&qedf->fipvlan_compl); mutex_init(&qedf->stats_mutex); + mutex_init(&qedf->flush_mutex); QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO, "QLogic FastLinQ FCoE Module qedf %s, " @@ -3068,6 +3220,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) goto err1; } + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", + qedf->dev_info.common.num_hwfns, + qed_ops->common->get_affin_hwfn_idx(qedf->cdev)); + /* queue allocation code should come here * order should be * slowpath_start @@ -3181,11 +3338,6 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) sprintf(host_buf, "host_%d", host->host_no); qed_ops->common->set_name(qedf->cdev, host_buf); - - /* Set xid max values */ - qedf->max_scsi_xid = QEDF_MAX_SCSI_XID; - qedf->max_els_xid = QEDF_MAX_ELS_XID; - /* Allocate cmd mgr */ qedf->cmd_mgr = qedf_cmd_mgr_alloc(qedf); if (!qedf->cmd_mgr) { @@ -3196,12 +3348,15 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) if (mode != QEDF_MODE_RECOVERY) { host->transportt = qedf_fc_transport_template; - host->can_queue = QEDF_MAX_ELS_XID; host->max_lun = qedf_max_lun; host->max_cmd_len = QEDF_MAX_CDB_LEN; + host->can_queue = FCOE_PARAMS_NUM_TASKS; rc = scsi_add_host(host, &pdev->dev); - if (rc) + if (rc) { + QEDF_WARN(&qedf->dbg_ctx, + "Error adding Scsi_Host rc=0x%x.\n", rc); goto err6; + } } memset(¶ms, 0, sizeof(params)); @@ -3377,7 +3532,9 @@ static void __qedf_remove(struct pci_dev *pdev, int mode) fcoe_ctlr_link_down(&qedf->ctlr); else fc_fabric_logoff(qedf->lport); - qedf_wait_for_upload(qedf); + + if (qedf_wait_for_upload(qedf) == false) + QEDF_ERR(&qedf->dbg_ctx, "Could not upload all sessions.\n"); #ifdef CONFIG_DEBUG_FS qedf_dbg_host_exit(&(qedf->dbg_ctx)); diff --git a/drivers/scsi/qedf/qedf_version.h b/drivers/scsi/qedf/qedf_version.h index 9455faacd5de..e57533de7e96 100644 --- a/drivers/scsi/qedf/qedf_version.h +++ b/drivers/scsi/qedf/qedf_version.h @@ -1,15 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic FCoE Offload Driver * Copyright (c) 2016-2018 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ -#define QEDF_VERSION "8.33.16.20" +#define QEDF_VERSION "8.37.25.20" #define QEDF_DRIVER_MAJOR_VER 8 -#define QEDF_DRIVER_MINOR_VER 33 -#define QEDF_DRIVER_REV_VER 16 +#define QEDF_DRIVER_MINOR_VER 37 +#define QEDF_DRIVER_REV_VER 25 #define QEDF_DRIVER_ENG_VER 20 diff --git a/drivers/scsi/qedi/Kconfig b/drivers/scsi/qedi/Kconfig index d1db92d24889..7ab07f3b453f 100644 --- a/drivers/scsi/qedi/Kconfig +++ b/drivers/scsi/qedi/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config QEDI tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support" depends on PCI && SCSI && UIO diff --git a/drivers/scsi/qedi/Makefile b/drivers/scsi/qedi/Makefile index 90a6925577cc..d84eedfd031b 100644 --- a/drivers/scsi/qedi/Makefile +++ b/drivers/scsi/qedi/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_QEDI) := qedi.o qedi-y := qedi_main.o qedi_iscsi.o qedi_fw.o qedi_sysfs.o \ qedi_dbg.o qedi_fw_api.o diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h index a26bb5066b90..9513fd320ffd 100644 --- a/drivers/scsi/qedi/qedi.h +++ b/drivers/scsi/qedi/qedi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDI_H_ diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c index 8fd28b056f73..2ebef4d20b5b 100644 --- a/drivers/scsi/qedi/qedi_dbg.c +++ b/drivers/scsi/qedi/qedi_dbg.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "qedi_dbg.h" @@ -16,10 +13,6 @@ qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -28,9 +21,9 @@ qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line, if (likely(qedi) && likely(qedi->pdev)) pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), - nfunc, line, qedi->host_no, &vaf); + func, line, qedi->host_no, &vaf); else - pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_err("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); va_end(va); } @@ -41,10 +34,6 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -56,9 +45,9 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, if (likely(qedi) && likely(qedi->pdev)) pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), - nfunc, line, qedi->host_no, &vaf); + func, line, qedi->host_no, &vaf); else - pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_warn("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); @@ -70,10 +59,6 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -85,10 +70,10 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, if (likely(qedi) && likely(qedi->pdev)) pr_notice("[%s]:[%s:%d]:%d: %pV", - dev_name(&qedi->pdev->dev), nfunc, line, + dev_name(&qedi->pdev->dev), func, line, qedi->host_no, &vaf); else - pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_notice("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); @@ -100,10 +85,6 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, { va_list va; struct va_format vaf; - char nfunc[32]; - - memset(nfunc, 0, sizeof(nfunc)); - memcpy(nfunc, func, sizeof(nfunc) - 1); va_start(va, fmt); @@ -115,9 +96,9 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, if (likely(qedi) && likely(qedi->pdev)) pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), - nfunc, line, qedi->host_no, &vaf); + func, line, qedi->host_no, &vaf); else - pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + pr_info("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf); ret: va_end(va); diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h index 0bc9c31d5a4f..243acc8b520a 100644 --- a/drivers/scsi/qedi/qedi_dbg.h +++ b/drivers/scsi/qedi/qedi_dbg.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDI_DBG_H_ diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c index 5667e4752e2e..42f5afb60055 100644 --- a/drivers/scsi/qedi/qedi_debugfs.c +++ b/drivers/scsi/qedi/qedi_debugfs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "qedi.h" diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index e2a995a6e8e7..946cebc4c932 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/blkdev.h> @@ -155,12 +152,10 @@ static void qedi_tmf_resp_work(struct work_struct *work) struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; struct iscsi_session *session = conn->session; struct iscsi_tm_rsp *resp_hdr_ptr; - struct iscsi_cls_session *cls_sess; int rval = 0; set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); resp_hdr_ptr = (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf; - cls_sess = iscsi_conn_to_session(qedi_conn->cls_conn); iscsi_block_session(session->cls_session); rval = qedi_cleanup_all_io(qedi, qedi_conn, qedi_cmd->task, true); @@ -985,7 +980,6 @@ static void qedi_ring_doorbell(struct qedi_conn *qedi_conn) * others they are two different assembly operations. */ wmb(); - mmiowb(); QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_MP_REQ, "prod_idx=0x%x, fw_prod_idx=0x%x, cid=0x%x\n", qedi_conn->ep->sq_prod_idx, qedi_conn->ep->fw_sq_prod_idx, @@ -1367,7 +1361,6 @@ static void qedi_tmf_work(struct work_struct *work) struct qedi_conn *qedi_conn = qedi_cmd->conn; struct qedi_ctx *qedi = qedi_conn->qedi; struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; - struct iscsi_cls_session *cls_sess; struct qedi_work_map *list_work = NULL; struct iscsi_task *mtask; struct qedi_cmd *cmd; @@ -1378,7 +1371,6 @@ static void qedi_tmf_work(struct work_struct *work) mtask = qedi_cmd->task; tmf_hdr = (struct iscsi_tm *)mtask->hdr; - cls_sess = iscsi_conn_to_session(qedi_conn->cls_conn); set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt); diff --git a/drivers/scsi/qedi/qedi_fw_api.c b/drivers/scsi/qedi/qedi_fw_api.c index 387dc87e4d22..52772904ef5d 100644 --- a/drivers/scsi/qedi/qedi_fw_api.c +++ b/drivers/scsi/qedi/qedi_fw_api.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/types.h> diff --git a/drivers/scsi/qedi/qedi_fw_iscsi.h b/drivers/scsi/qedi/qedi_fw_iscsi.h index c3deb77ac388..10f19f0af0a3 100644 --- a/drivers/scsi/qedi/qedi_fw_iscsi.h +++ b/drivers/scsi/qedi/qedi_fw_iscsi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDI_FW_ISCSI_H_ diff --git a/drivers/scsi/qedi/qedi_fw_scsi.h b/drivers/scsi/qedi/qedi_fw_scsi.h index cdaf918f1019..2524f9f3cf9e 100644 --- a/drivers/scsi/qedi/qedi_fw_scsi.h +++ b/drivers/scsi/qedi/qedi_fw_scsi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDI_FW_SCSI_H_ diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h index a2aa06ed1620..8ba7c771ce4d 100644 --- a/drivers/scsi/qedi/qedi_gbl.h +++ b/drivers/scsi/qedi/qedi_gbl.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDI_GBL_H_ diff --git a/drivers/scsi/qedi/qedi_hsi.h b/drivers/scsi/qedi/qedi_hsi.h index 8ca44c78f093..d82ab99acb04 100644 --- a/drivers/scsi/qedi/qedi_hsi.h +++ b/drivers/scsi/qedi/qedi_hsi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef __QEDI_HSI__ #define __QEDI_HSI__ diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 6d6d6013e35b..8829880a54c3 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/blkdev.h> @@ -579,7 +576,7 @@ static int qedi_conn_start(struct iscsi_cls_conn *cls_conn) rval = qedi_iscsi_update_conn(qedi, qedi_conn); if (rval) { iscsi_conn_printk(KERN_ALERT, conn, - "conn_start: FW oflload conn failed.\n"); + "conn_start: FW offload conn failed.\n"); rval = -EINVAL; goto start_err; } @@ -590,7 +587,7 @@ static int qedi_conn_start(struct iscsi_cls_conn *cls_conn) rval = iscsi_conn_start(cls_conn); if (rval) { iscsi_conn_printk(KERN_ALERT, conn, - "iscsi_conn_start: FW oflload conn failed!!\n"); + "iscsi_conn_start: FW offload conn failed!!\n"); } start_err: @@ -809,8 +806,6 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, struct qedi_endpoint *qedi_ep; struct sockaddr_in *addr; struct sockaddr_in6 *addr6; - struct qed_dev *cdev = NULL; - struct qedi_uio_dev *udev = NULL; struct iscsi_path path_req; u32 msg_type = ISCSI_KEVENT_IF_DOWN; u32 iscsi_cid = QEDI_CID_RESERVED; @@ -830,8 +825,6 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, } qedi = iscsi_host_priv(shost); - cdev = qedi->cdev; - udev = qedi->udev; if (test_bit(QEDI_IN_OFFLINE, &qedi->flags) || test_bit(QEDI_IN_RECOVERY, &qedi->flags)) { @@ -993,13 +986,17 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep) struct iscsi_conn *conn = NULL; struct qedi_ctx *qedi; int ret = 0; - int wait_delay = 20 * HZ; + int wait_delay; int abrt_conn = 0; int count = 10; + wait_delay = 60 * HZ + DEF_MAX_RT_TIME; qedi_ep = ep->dd_data; qedi = qedi_ep->qedi; + if (qedi_ep->state == EP_STATE_OFLDCONN_START) + goto ep_exit_recover; + flush_work(&qedi_ep->offload_work); if (qedi_ep->conn) { @@ -1163,7 +1160,7 @@ static void qedi_offload_work(struct work_struct *work) struct qedi_endpoint *qedi_ep = container_of(work, struct qedi_endpoint, offload_work); struct qedi_ctx *qedi; - int wait_delay = 20 * HZ; + int wait_delay = 5 * HZ; int ret; qedi = qedi_ep->qedi; diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h index 892d70d54553..67c3b7349271 100644 --- a/drivers/scsi/qedi/qedi_iscsi.h +++ b/drivers/scsi/qedi/qedi_iscsi.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef _QEDI_ISCSI_H_ diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index e5db9a9954dc..acb930b8c6a6 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include <linux/module.h> @@ -990,6 +987,9 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi, if (!iscsi_is_session_online(cls_sess)) continue; + if (!sess->targetname) + continue; + if (pri_ctrl_flags) { if (!strcmp(pri_tgt->iscsi_name, sess->targetname) && !strcmp(pri_tgt->ip_addr, ep_ip_addr)) { @@ -1313,13 +1313,20 @@ static void qedi_simd_int_handler(void *cookie) static void qedi_sync_free_irqs(struct qedi_ctx *qedi) { int i; + u16 idx; if (qedi->int_info.msix_cnt) { for (i = 0; i < qedi->int_info.used_cnt; i++) { - synchronize_irq(qedi->int_info.msix[i].vector); - irq_set_affinity_hint(qedi->int_info.msix[i].vector, + idx = i * qedi->dev_info.common.num_hwfns + + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Freeing IRQ #%d vector_idx=%d.\n", i, idx); + + synchronize_irq(qedi->int_info.msix[idx].vector); + irq_set_affinity_hint(qedi->int_info.msix[idx].vector, NULL); - free_irq(qedi->int_info.msix[i].vector, + free_irq(qedi->int_info.msix[idx].vector, &qedi->fp_array[i]); } } else { @@ -1334,20 +1341,28 @@ static void qedi_sync_free_irqs(struct qedi_ctx *qedi) static int qedi_request_msix_irq(struct qedi_ctx *qedi) { int i, rc, cpu; + u16 idx; cpu = cpumask_first(cpu_online_mask); - for (i = 0; i < qedi->int_info.msix_cnt; i++) { - rc = request_irq(qedi->int_info.msix[i].vector, + for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) { + idx = i * qedi->dev_info.common.num_hwfns + + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", + qedi->dev_info.common.num_hwfns, + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); + + rc = request_irq(qedi->int_info.msix[idx].vector, qedi_msix_handler, 0, "qedi", &qedi->fp_array[i]); - if (rc) { QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); qedi_sync_free_irqs(qedi); return rc; } qedi->int_info.used_cnt++; - rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector, + rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector, get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } @@ -2415,6 +2430,11 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) if (rc) goto free_host; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", + qedi->dev_info.common.num_hwfns, + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); + if (mode != QEDI_MODE_RECOVERY) { rc = qedi_set_iscsi_pf_param(qedi); if (rc) { diff --git a/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h b/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h index df39b69b366d..760864e43680 100644 --- a/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h +++ b/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #ifndef NVM_ISCSI_CFG_H diff --git a/drivers/scsi/qedi/qedi_sysfs.c b/drivers/scsi/qedi/qedi_sysfs.c index b10c48bd1428..04ee68e6499c 100644 --- a/drivers/scsi/qedi/qedi_sysfs.c +++ b/drivers/scsi/qedi/qedi_sysfs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ #include "qedi.h" diff --git a/drivers/scsi/qedi/qedi_version.h b/drivers/scsi/qedi/qedi_version.h index 41bcbbafebd4..0ac1055bd420 100644 --- a/drivers/scsi/qedi/qedi_version.h +++ b/drivers/scsi/qedi/qedi_version.h @@ -1,14 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * QLogic iSCSI Offload Driver * Copyright (c) 2016 Cavium Inc. - * - * This software is available under the terms of the GNU General Public License - * (GPL) Version 2, available from the file COPYING in the main directory of - * this source tree. */ -#define QEDI_MODULE_VERSION "8.33.0.21" +#define QEDI_MODULE_VERSION "8.37.0.20" #define QEDI_DRIVER_MAJOR_VER 8 -#define QEDI_DRIVER_MINOR_VER 33 +#define QEDI_DRIVER_MINOR_VER 37 #define QEDI_DRIVER_REV_VER 0 -#define QEDI_DRIVER_ENG_VER 21 +#define QEDI_DRIVER_ENG_VER 20 diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 6856dfdfa473..e5760c4a27f0 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /****************************************************************************** * QLOGIC LINUX SOFTWARE * @@ -6,16 +7,6 @@ * Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc. * Copyright (C) 2003-2004 Christoph Hellwig * -* 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 QLA1280_VERSION "3.27.1" /***************************************************************************** @@ -3004,8 +2995,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) sp->flags |= SRB_SENT; ha->actthreads++; WRT_REG_WORD(®->mailbox4, ha->req_ring_index); - /* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */ - mmiowb(); out: if (status) @@ -3254,8 +3243,6 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) sp->flags |= SRB_SENT; ha->actthreads++; WRT_REG_WORD(®->mailbox4, ha->req_ring_index); - /* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */ - mmiowb(); out: if (status) @@ -3367,19 +3354,8 @@ qla1280_isp_cmd(struct scsi_qla_host *ha) /* * Update request index to mailbox4 (Request Queue In). - * The mmiowb() ensures that this write is ordered with writes by other - * CPUs. Without the mmiowb(), it is possible for the following: - * CPUA posts write of index 5 to mailbox4 - * CPUA releases host lock - * CPUB acquires host lock - * CPUB posts write of index 6 to mailbox4 - * On PCI bus, order reverses and write of 6 posts, then index 5, - * causing chip to issue full queue of stale commands - * The mmiowb() prevents future writes from crossing the barrier. - * See Documentation/driver-api/device-io.rst for more information. */ WRT_REG_WORD(®->mailbox4, ha->req_ring_index); - mmiowb(); LEAVE("qla1280_isp_cmd"); } diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 1522aca2c8c8..b496206362a9 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /****************************************************************************** * QLOGIC LINUX SOFTWARE * @@ -5,16 +6,6 @@ * Copyright (C) 2000 Qlogic Corporation * (www.qlogic.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 _QLA1280_H diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig index 036cc3f217b1..764501838e21 100644 --- a/drivers/scsi/qla2xxx/Kconfig +++ b/drivers/scsi/qla2xxx/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_QLA_FC tristate "QLogic QLA2XXX Fibre Channel Support" depends on PCI && SCSI diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index f928c4d3a1ef..8d560c562e9c 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -29,24 +29,27 @@ qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj, if (!(ha->fw_dump_reading || ha->mctp_dump_reading)) return 0; + mutex_lock(&ha->optrom_mutex); if (IS_P3P_TYPE(ha)) { if (off < ha->md_template_size) { rval = memory_read_from_buffer(buf, count, &off, ha->md_tmplt_hdr, ha->md_template_size); - return rval; + } else { + off -= ha->md_template_size; + rval = memory_read_from_buffer(buf, count, + &off, ha->md_dump, ha->md_dump_size); } - off -= ha->md_template_size; - rval = memory_read_from_buffer(buf, count, - &off, ha->md_dump, ha->md_dump_size); - return rval; - } else if (ha->mctp_dumped && ha->mctp_dump_reading) - return memory_read_from_buffer(buf, count, &off, ha->mctp_dump, + } else if (ha->mctp_dumped && ha->mctp_dump_reading) { + rval = memory_read_from_buffer(buf, count, &off, ha->mctp_dump, MCTP_DUMP_SIZE); - else if (ha->fw_dump_reading) - return memory_read_from_buffer(buf, count, &off, ha->fw_dump, + } else if (ha->fw_dump_reading) { + rval = memory_read_from_buffer(buf, count, &off, ha->fw_dump, ha->fw_dump_len); - else - return 0; + } else { + rval = 0; + } + mutex_unlock(&ha->optrom_mutex); + return rval; } static ssize_t @@ -154,6 +157,8 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj, struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); struct qla_hw_data *ha = vha->hw; + uint32_t faddr; + struct active_regions active_regions = { }; if (!capable(CAP_SYS_ADMIN)) return 0; @@ -164,11 +169,21 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj, return -EAGAIN; } - if (IS_NOCACHE_VPD_TYPE(ha)) - ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, - ha->nvram_size); + if (!IS_NOCACHE_VPD_TYPE(ha)) { + mutex_unlock(&ha->optrom_mutex); + goto skip; + } + + faddr = ha->flt_region_nvram; + if (IS_QLA28XX(ha)) { + if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE) + faddr = ha->flt_region_nvram_sec; + } + ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size); + mutex_unlock(&ha->optrom_mutex); +skip: return memory_read_from_buffer(buf, count, &off, ha->nvram, ha->nvram_size); } @@ -223,9 +238,9 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj, } /* Write NVRAM. */ - ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count); - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base, - count); + ha->isp_ops->write_nvram(vha, buf, ha->nvram_base, count); + ha->isp_ops->read_nvram(vha, ha->nvram, ha->nvram_base, + count); mutex_unlock(&ha->optrom_mutex); ql_dbg(ql_dbg_user, vha, 0x7060, @@ -364,7 +379,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, } ha->optrom_region_start = start; - ha->optrom_region_size = start + size; + ha->optrom_region_size = size; ha->optrom_state = QLA_SREADING; ha->optrom_buffer = vmalloc(ha->optrom_region_size); @@ -418,6 +433,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, * 0x000000 -> 0x07ffff -- Boot code. * 0x080000 -> 0x0fffff -- Firmware. * 0x120000 -> 0x12ffff -- VPD and HBA parameters. + * + * > ISP25xx type boards: + * + * None -- should go through BSG. */ valid = 0; if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) @@ -425,9 +444,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, else if (start == (ha->flt_region_boot * 4) || start == (ha->flt_region_fw * 4)) valid = 1; - else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) - || IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) - || IS_QLA27XX(ha)) + else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) valid = 1; if (!valid) { ql_log(ql_log_warn, vha, 0x7065, @@ -437,7 +454,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, } ha->optrom_region_start = start; - ha->optrom_region_size = start + size; + ha->optrom_region_size = size; ha->optrom_state = QLA_SWRITING; ha->optrom_buffer = vmalloc(ha->optrom_region_size); @@ -504,6 +521,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, struct device, kobj))); struct qla_hw_data *ha = vha->hw; uint32_t faddr; + struct active_regions active_regions = { }; if (unlikely(pci_channel_offline(ha->pdev))) return -EAGAIN; @@ -511,22 +529,33 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return -EINVAL; - if (IS_NOCACHE_VPD_TYPE(ha)) { - faddr = ha->flt_region_vpd << 2; + if (IS_NOCACHE_VPD_TYPE(ha)) + goto skip; + + faddr = ha->flt_region_vpd << 2; - if (IS_QLA27XX(ha) && - qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE) + if (IS_QLA28XX(ha)) { + qla28xx_get_aux_images(vha, &active_regions); + if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE) faddr = ha->flt_region_vpd_sec << 2; - mutex_lock(&ha->optrom_mutex); - if (qla2x00_chip_is_down(vha)) { - mutex_unlock(&ha->optrom_mutex); - return -EAGAIN; - } - ha->isp_ops->read_optrom(vha, ha->vpd, faddr, - ha->vpd_size); + ql_dbg(ql_dbg_init, vha, 0x7070, + "Loading %s nvram image.\n", + active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? + "primary" : "secondary"); + } + + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; } + + ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size); + mutex_unlock(&ha->optrom_mutex); + + ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size); +skip: return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size); } @@ -563,8 +592,8 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, } /* Write NVRAM. */ - ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count); - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count); + ha->isp_ops->write_nvram(vha, buf, ha->vpd_base, count); + ha->isp_ops->read_nvram(vha, ha->vpd, ha->vpd_base, count); /* Update flash version information for 4Gb & above. */ if (!IS_FWI2_CAPABLE(ha)) { @@ -645,6 +674,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, int type; uint32_t idc_control; uint8_t *tmp_data = NULL; + if (off != 0) return -EINVAL; @@ -682,7 +712,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, ql_log(ql_log_info, vha, 0x706f, "Issuing MPI reset.\n"); - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { uint32_t idc_control; qla83xx_idc_lock(vha, 0); @@ -858,7 +888,7 @@ do_read: count = 0; } - count = actual_size > count ? count: actual_size; + count = actual_size > count ? count : actual_size; memcpy(buf, ha->xgmac_data, count); return count; @@ -934,7 +964,7 @@ static struct bin_attribute sysfs_dcbx_tlv_attr = { static struct sysfs_entry { char *name; struct bin_attribute *attr; - int is4GBp_only; + int type; } bin_file_entries[] = { { "fw_dump", &sysfs_fw_dump_attr, }, { "nvram", &sysfs_nvram_attr, }, @@ -957,11 +987,11 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) int ret; for (iter = bin_file_entries; iter->name; iter++) { - if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) + if (iter->type && !IS_FWI2_CAPABLE(vha->hw)) continue; - if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) + if (iter->type == 2 && !IS_QLA25XX(vha->hw)) continue; - if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw))) + if (iter->type == 3 && !(IS_CNA_CAPABLE(vha->hw))) continue; ret = sysfs_create_bin_file(&host->shost_gendev.kobj, @@ -985,13 +1015,14 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon) struct qla_hw_data *ha = vha->hw; for (iter = bin_file_entries; iter->name; iter++) { - if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) + if (iter->type && !IS_FWI2_CAPABLE(ha)) continue; - if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) + if (iter->type == 2 && !IS_QLA25XX(ha)) continue; - if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw))) + if (iter->type == 3 && !(IS_CNA_CAPABLE(ha))) continue; - if (iter->is4GBp_only == 0x27 && !IS_QLA27XX(vha->hw)) + if (iter->type == 0x27 && + (!IS_QLA27XX(ha) || !IS_QLA28XX(ha))) continue; sysfs_remove_bin_file(&host->shost_gendev.kobj, @@ -1049,6 +1080,7 @@ qla2x00_isp_name_show(struct device *dev, struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + return scnprintf(buf, PAGE_SIZE, "ISP%04X\n", vha->hw->pdev->device); } @@ -1082,6 +1114,7 @@ qla2x00_model_desc_show(struct device *dev, struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + return scnprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_desc); } @@ -1294,6 +1327,7 @@ qla2x00_optrom_bios_version_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; + return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1], ha->bios_revision[0]); } @@ -1304,6 +1338,7 @@ qla2x00_optrom_efi_version_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; + return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1], ha->efi_revision[0]); } @@ -1314,6 +1349,7 @@ qla2x00_optrom_fcode_version_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; + return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1], ha->fcode_revision[0]); } @@ -1324,6 +1360,7 @@ qla2x00_optrom_fw_version_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; + return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n", ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2], ha->fw_revision[3]); @@ -1336,7 +1373,8 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev, scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n", @@ -1349,6 +1387,7 @@ qla2x00_total_isp_aborts_show(struct device *dev, struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + return scnprintf(buf, PAGE_SIZE, "%d\n", vha->qla_stats.total_isp_aborts); } @@ -1358,24 +1397,40 @@ qla24xx_84xx_fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { int rval = QLA_SUCCESS; - uint16_t status[2] = {0, 0}; + uint16_t status[2] = { 0 }; scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; if (!IS_QLA84XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); - if (ha->cs84xx->op_fw_version == 0) + if (!ha->cs84xx->op_fw_version) { rval = qla84xx_verify_chip(vha, status); - if ((rval == QLA_SUCCESS) && (status[0] == 0)) - return scnprintf(buf, PAGE_SIZE, "%u\n", - (uint32_t)ha->cs84xx->op_fw_version); + if (!rval && !status[0]) + return scnprintf(buf, PAGE_SIZE, "%u\n", + (uint32_t)ha->cs84xx->op_fw_version); + } return scnprintf(buf, PAGE_SIZE, "\n"); } static ssize_t +qla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n", + ha->serdes_version[0], ha->serdes_version[1], + ha->serdes_version[2]); +} + +static ssize_t qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1383,7 +1438,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, struct qla_hw_data *ha = vha->hw; if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", @@ -1596,7 +1651,7 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr, scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n", @@ -1604,35 +1659,38 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr, } static ssize_t -qla2x00_min_link_speed_show(struct device *dev, struct device_attribute *attr, - char *buf) +qla2x00_min_supported_speed_show(struct device *dev, + struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); return scnprintf(buf, PAGE_SIZE, "%s\n", - ha->min_link_speed == 5 ? "32Gps" : - ha->min_link_speed == 4 ? "16Gps" : - ha->min_link_speed == 3 ? "8Gps" : - ha->min_link_speed == 2 ? "4Gps" : - ha->min_link_speed != 0 ? "unknown" : ""); + ha->min_supported_speed == 6 ? "64Gps" : + ha->min_supported_speed == 5 ? "32Gps" : + ha->min_supported_speed == 4 ? "16Gps" : + ha->min_supported_speed == 3 ? "8Gps" : + ha->min_supported_speed == 2 ? "4Gps" : + ha->min_supported_speed != 0 ? "unknown" : ""); } static ssize_t -qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr, - char *buf) +qla2x00_max_supported_speed_show(struct device *dev, + struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); return scnprintf(buf, PAGE_SIZE, "%s\n", - ha->max_speed_sup ? "32Gps" : "16Gps"); + ha->max_supported_speed == 2 ? "64Gps" : + ha->max_supported_speed == 1 ? "32Gps" : + ha->max_supported_speed == 0 ? "16Gps" : "unknown"); } static ssize_t @@ -1645,7 +1703,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr, int mode = QLA_SET_DATA_RATE_LR; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA27XX(vha->hw)) { + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) { ql_log(ql_log_warn, vha, 0x70d8, "Speed setting not supported \n"); return -EINVAL; @@ -2164,6 +2222,32 @@ qla2x00_dif_bundle_statistics_show(struct device *dev, ha->dif_bundle_dma_allocs, ha->pool.unusable.count); } +static ssize_t +qla2x00_fw_attr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%llx\n", + (uint64_t)ha->fw_attributes_ext[1] << 48 | + (uint64_t)ha->fw_attributes_ext[0] << 32 | + (uint64_t)ha->fw_attributes_h << 16 | + (uint64_t)ha->fw_attributes); +} + +static ssize_t +qla2x00_port_no_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + return scnprintf(buf, PAGE_SIZE, "%u\n", vha->hw->port_no); +} + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -2192,6 +2276,7 @@ static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, NULL); static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, NULL); +static DEVICE_ATTR(serdes_version, 0444, qla2x00_serdes_version_show, NULL); static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL); static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show, @@ -2209,8 +2294,10 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR, qla2x00_allow_cna_fw_dump_show, qla2x00_allow_cna_fw_dump_store); static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL); -static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL); -static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL); +static DEVICE_ATTR(min_supported_speed, 0444, + qla2x00_min_supported_speed_show, NULL); +static DEVICE_ATTR(max_supported_speed, 0444, + qla2x00_max_supported_speed_show, NULL); static DEVICE_ATTR(zio_threshold, 0644, qla_zio_threshold_show, qla_zio_threshold_store); @@ -2221,6 +2308,8 @@ static DEVICE_ATTR(dif_bundle_statistics, 0444, qla2x00_dif_bundle_statistics_show, NULL); static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show, qla2x00_port_speed_store); +static DEVICE_ATTR(port_no, 0444, qla2x00_port_no_show, NULL); +static DEVICE_ATTR(fw_attr, 0444, qla2x00_fw_attr_show, NULL); struct device_attribute *qla2x00_host_attrs[] = { @@ -2242,6 +2331,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_optrom_fw_version, &dev_attr_84xx_fw_version, &dev_attr_total_isp_aborts, + &dev_attr_serdes_version, &dev_attr_mpi_version, &dev_attr_phy_version, &dev_attr_flash_block_size, @@ -2256,11 +2346,13 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_fw_dump_size, &dev_attr_allow_cna_fw_dump, &dev_attr_pep_version, - &dev_attr_min_link_speed, - &dev_attr_max_speed_sup, + &dev_attr_min_supported_speed, + &dev_attr_max_supported_speed, &dev_attr_zio_threshold, &dev_attr_dif_bundle_statistics, &dev_attr_port_speed, + &dev_attr_port_no, + &dev_attr_fw_attr, NULL, /* reserve for qlini_mode */ NULL, /* reserve for ql2xiniexchg */ NULL, /* reserve for ql2xexchoffld */ @@ -2296,16 +2388,15 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost) static void qla2x00_get_host_speed(struct Scsi_Host *shost) { - struct qla_hw_data *ha = ((struct scsi_qla_host *) - (shost_priv(shost)))->hw; - u32 speed = FC_PORTSPEED_UNKNOWN; + scsi_qla_host_t *vha = shost_priv(shost); + u32 speed; - if (IS_QLAFX00(ha)) { + if (IS_QLAFX00(vha->hw)) { qlafx00_get_host_speed(shost); return; } - switch (ha->link_data_rate) { + switch (vha->hw->link_data_rate) { case PORT_SPEED_1GB: speed = FC_PORTSPEED_1GBIT; break; @@ -2327,7 +2418,14 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) case PORT_SPEED_32GB: speed = FC_PORTSPEED_32GBIT; break; + case PORT_SPEED_64GB: + speed = FC_PORTSPEED_64GBIT; + break; + default: + speed = FC_PORTSPEED_UNKNOWN; + break; } + fc_host_speed(shost) = speed; } @@ -2335,7 +2433,7 @@ static void qla2x00_get_host_port_type(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); - uint32_t port_type = FC_PORTTYPE_UNKNOWN; + uint32_t port_type; if (vha->vp_idx) { fc_host_port_type(shost) = FC_PORTTYPE_NPIV; @@ -2354,7 +2452,11 @@ qla2x00_get_host_port_type(struct Scsi_Host *shost) case ISP_CFG_F: port_type = FC_PORTTYPE_NPORT; break; + default: + port_type = FC_PORTTYPE_UNKNOWN; + break; } + fc_host_port_type(shost) = port_type; } @@ -2416,13 +2518,10 @@ qla2x00_get_starget_port_id(struct scsi_target *starget) fc_starget_port_id(starget) = port_id; } -static void +static inline void qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) { - if (timeout) - rport->dev_loss_tmo = timeout; - else - rport->dev_loss_tmo = 1; + rport->dev_loss_tmo = timeout ? timeout : 1; } static void @@ -2632,8 +2731,9 @@ static void qla2x00_get_host_fabric_name(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); - uint8_t node_name[WWN_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, \ - 0xFF, 0xFF, 0xFF, 0xFF}; + static const uint8_t node_name[WWN_SIZE] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; u64 fabric_name = wwn_to_u64(node_name); if (vha->device_flags & SWITCH_FOUND) @@ -2711,8 +2811,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) /* initialized vport states */ atomic_set(&vha->loop_state, LOOP_DOWN); - vha->vp_err_state= VP_ERR_PORTDWN; - vha->vp_prev_err_state= VP_ERR_UNKWN; + vha->vp_err_state = VP_ERR_PORTDWN; + vha->vp_prev_err_state = VP_ERR_UNKWN; /* Check if physical ha port is Up */ if (atomic_read(&base_vha->loop_state) == LOOP_DOWN || atomic_read(&base_vha->loop_state) == LOOP_DEAD) { @@ -2727,6 +2827,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { int prot = 0, guard; + vha->flags.difdix_supported = 1; ql_dbg(ql_dbg_user, vha, 0x7082, "Registered for DIF/DIX type 1 and 3 protection.\n"); @@ -2977,7 +3078,7 @@ void qla2x00_init_host_attr(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; - u32 speed = FC_PORTSPEED_UNKNOWN; + u32 speeds = FC_PORTSPEED_UNKNOWN; fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); @@ -2988,25 +3089,45 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; if (IS_CNA_CAPABLE(ha)) - speed = FC_PORTSPEED_10GBIT; - else if (IS_QLA2031(ha)) - speed = FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT; - else if (IS_QLA25XX(ha)) - speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | - FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + speeds = FC_PORTSPEED_10GBIT; + else if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) { + if (ha->max_supported_speed == 2) { + if (ha->min_supported_speed <= 6) + speeds |= FC_PORTSPEED_64GBIT; + } + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1) { + if (ha->min_supported_speed <= 5) + speeds |= FC_PORTSPEED_32GBIT; + } + if (ha->max_supported_speed == 2 || + ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 4) + speeds |= FC_PORTSPEED_16GBIT; + } + if (ha->max_supported_speed == 1 || + ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 3) + speeds |= FC_PORTSPEED_8GBIT; + } + if (ha->max_supported_speed == 0) { + if (ha->min_supported_speed <= 2) + speeds |= FC_PORTSPEED_4GBIT; + } + } else if (IS_QLA2031(ha)) + speeds = FC_PORTSPEED_16GBIT|FC_PORTSPEED_8GBIT| + FC_PORTSPEED_4GBIT; + else if (IS_QLA25XX(ha) || IS_QLAFX00(ha)) + speeds = FC_PORTSPEED_8GBIT|FC_PORTSPEED_4GBIT| + FC_PORTSPEED_2GBIT|FC_PORTSPEED_1GBIT; else if (IS_QLA24XX_TYPE(ha)) - speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | - FC_PORTSPEED_1GBIT; + speeds = FC_PORTSPEED_4GBIT|FC_PORTSPEED_2GBIT| + FC_PORTSPEED_1GBIT; else if (IS_QLA23XX(ha)) - speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; - else if (IS_QLAFX00(ha)) - speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | - FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; - else if (IS_QLA27XX(ha)) - speed = FC_PORTSPEED_32GBIT | FC_PORTSPEED_16GBIT | - FC_PORTSPEED_8GBIT; + speeds = FC_PORTSPEED_2GBIT|FC_PORTSPEED_1GBIT; else - speed = FC_PORTSPEED_1GBIT; - fc_host_supported_speeds(vha->host) = speed; + speeds = FC_PORTSPEED_1GBIT; + + fc_host_supported_speeds(vha->host) = speeds; } diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 17d42658ad9a..5441557b424b 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1,4 +1,4 @@ - /* +/* * QLogic Fibre Channel HBA Driver * Copyright (c) 2003-2014 QLogic Corporation * @@ -84,8 +84,7 @@ qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha, return 0; } - if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' || - bcode[3] != 'S') { + if (memcmp(bcode, "HQOS", 4)) { /* Invalid FCP priority data header*/ ql_dbg(ql_dbg_user, vha, 0x7052, "Invalid FCP Priority data header. bcode=0x%x.\n", @@ -1044,7 +1043,7 @@ 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))); + fw_ver = get_unaligned_le32((uint32_t *)fw_buf + 2); mn->entry_type = VERIFY_CHIP_IOCB_TYPE; mn->entry_count = 1; @@ -1057,9 +1056,8 @@ qla84xx_updatefw(struct bsg_job *bsg_job) mn->fw_ver = cpu_to_le32(fw_ver); mn->fw_size = cpu_to_le32(data_len); mn->fw_seq_size = cpu_to_le32(data_len); - mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma)); - mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma)); - mn->dseg_length = cpu_to_le32(data_len); + put_unaligned_le64(fw_dma, &mn->dsd.address); + mn->dsd.length = cpu_to_le32(data_len); mn->data_seg_cnt = cpu_to_le16(1); rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); @@ -1238,9 +1236,8 @@ qla84xx_mgmt_cmd(struct bsg_job *bsg_job) if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) { mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len); mn->dseg_count = cpu_to_le16(1); - mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); - mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); - mn->dseg_length = cpu_to_le32(ql84_mgmt->mgmt.len); + put_unaligned_le64(mgmt_dma, &mn->dsd.address); + mn->dsd.length = cpu_to_le32(ql84_mgmt->mgmt.len); } rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0); @@ -1354,7 +1351,7 @@ qla24xx_iidma(struct bsg_job *bsg_job) if (rval) { ql_log(ql_log_warn, vha, 0x704c, - "iIDMA cmd failed for %8phN -- " + "iiDMA cmd failed for %8phN -- " "%04x %x %04x %04x.\n", fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]); rval = (DID_ERROR << 16); @@ -1412,7 +1409,8 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha, start == (ha->flt_region_fw * 4)) valid = 1; else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || - IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) + IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) valid = 1; if (!valid) { ql_log(ql_log_warn, vha, 0x7058, @@ -1534,6 +1532,7 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job) uint32_t count; dma_addr_t sfp_dma; void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_NO_MEMORY; @@ -1584,6 +1583,7 @@ qla2x00_read_fru_status(struct bsg_job *bsg_job) struct qla_status_reg *sr = (void *)bsg; dma_addr_t sfp_dma; uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_NO_MEMORY; @@ -1634,6 +1634,7 @@ qla2x00_write_fru_status(struct bsg_job *bsg_job) struct qla_status_reg *sr = (void *)bsg; dma_addr_t sfp_dma; uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_NO_MEMORY; @@ -1680,6 +1681,7 @@ qla2x00_write_i2c(struct bsg_job *bsg_job) struct qla_i2c_access *i2c = (void *)bsg; dma_addr_t sfp_dma; uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_NO_MEMORY; @@ -1725,6 +1727,7 @@ qla2x00_read_i2c(struct bsg_job *bsg_job) struct qla_i2c_access *i2c = (void *)bsg; dma_addr_t sfp_dma; uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_NO_MEMORY; @@ -1961,7 +1964,7 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job) /* Dump the vendor information */ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf, - (uint8_t *)piocb_rqst, sizeof(struct qla_mt_iocb_rqst_fx00)); + piocb_rqst, sizeof(*piocb_rqst)); if (!vha->flags.online) { ql_log(ql_log_warn, vha, 0x70d0, @@ -2157,7 +2160,7 @@ qla27xx_get_flash_upd_cap(struct bsg_job *bsg_job) struct qla_hw_data *ha = vha->hw; struct qla_flash_update_caps cap; - if (!(IS_QLA27XX(ha))) + if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha)) return -EPERM; memset(&cap, 0, sizeof(cap)); @@ -2190,7 +2193,7 @@ qla27xx_set_flash_upd_cap(struct bsg_job *bsg_job) uint64_t online_fw_attr = 0; struct qla_flash_update_caps cap; - if (!(IS_QLA27XX(ha))) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return -EPERM; memset(&cap, 0, sizeof(cap)); @@ -2238,7 +2241,7 @@ qla27xx_get_bbcr_data(struct bsg_job *bsg_job) uint8_t domain, area, al_pa, state; int rval; - if (!(IS_QLA27XX(ha))) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return -EPERM; memset(&bbcr, 0, sizeof(bbcr)); @@ -2323,8 +2326,8 @@ qla2x00_get_priv_stats(struct bsg_job *bsg_job) rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options); if (rval == QLA_SUCCESS) { - ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3, - (uint8_t *)stats, sizeof(*stats)); + ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e5, + stats, sizeof(*stats)); sg_copy_from_buffer(bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats)); } @@ -2353,7 +2356,8 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) int rval; struct qla_dport_diag *dd; - if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw)) + if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && + !IS_QLA28XX(vha->hw)) return -EPERM; dd = kmalloc(sizeof(*dd), GFP_KERNEL); @@ -2388,6 +2392,45 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) } static int +qla2x00_get_flash_image_status(struct bsg_job *bsg_job) +{ + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct qla_hw_data *ha = vha->hw; + struct qla_active_regions regions = { }; + struct active_regions active_regions = { }; + + qla28xx_get_aux_images(vha, &active_regions); + regions.global_image = active_regions.global; + + if (IS_QLA28XX(ha)) { + qla27xx_get_active_image(vha, &active_regions); + regions.board_config = active_regions.aux.board_config; + regions.vpd_nvram = active_regions.aux.vpd_nvram; + regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1; + regions.npiv_config_2_3 = active_regions.aux.npiv_config_2_3; + } + + ql_dbg(ql_dbg_user, vha, 0x70e1, + "%s(%lu): FW=%u BCFG=%u VPDNVR=%u NPIV01=%u NPIV02=%u\n", + __func__, vha->host_no, regions.global_image, + regions.board_config, regions.vpd_nvram, + regions.npiv_config_0_1, regions.npiv_config_2_3); + + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, ®ions, sizeof(regions)); + + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + bsg_reply->reply_payload_rcv_len = sizeof(regions); + bsg_reply->result = DID_OK << 16; + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + + return 0; +} + +static int qla2x00_process_vendor_specific(struct bsg_job *bsg_job) { struct fc_bsg_request *bsg_request = bsg_job->request; @@ -2460,6 +2503,9 @@ qla2x00_process_vendor_specific(struct bsg_job *bsg_job) case QL_VND_DPORT_DIAGNOSTICS: return qla2x00_do_dport_diagnostics(bsg_job); + case QL_VND_SS_GET_FLASH_IMAGE_STATUS: + return qla2x00_get_flash_image_status(bsg_job); + default: return -ENOSYS; } diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index d97dfd521356..7594fad7b5b5 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -31,6 +31,7 @@ #define QL_VND_GET_PRIV_STATS 0x18 #define QL_VND_DPORT_DIAGNOSTICS 0x19 #define QL_VND_GET_PRIV_STATS_EX 0x1A +#define QL_VND_SS_GET_FLASH_IMAGE_STATUS 0x1E /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 @@ -279,4 +280,14 @@ struct qla_dport_diag { #define QLA_DPORT_RESULT 0x0 #define QLA_DPORT_START 0x2 +/* active images in flash */ +struct qla_active_regions { + uint8_t global_image; + uint8_t board_config; + uint8_t vpd_nvram; + uint8_t npiv_config_0_1; + uint8_t npiv_config_2_3; + uint8_t reserved[32]; +} __packed; + #endif diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index c7533fa7f46e..9e80646722e2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -111,30 +111,25 @@ int qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, uint32_t ram_dwords, void **nxt) { - int rval; - uint32_t cnt, stat, timer, dwords, idx; - uint16_t mb0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; dma_addr_t dump_dma = ha->gid_list_dma; - uint32_t *dump = (uint32_t *)ha->gid_list; - - rval = QLA_SUCCESS; - mb0 = 0; + uint32_t *chunk = (void *)ha->gid_list; + uint32_t dwords = qla2x00_gid_list_size(ha) / 4; + uint32_t stat; + ulong i, j, timer = 6000000; + int rval = QLA_FUNCTION_FAILED; - WRT_REG_WORD(®->mailbox0, MBC_LOAD_DUMP_MPI_RAM); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + for (i = 0; i < ram_dwords; i += dwords, addr += dwords) { + if (i + dwords > ram_dwords) + dwords = ram_dwords - i; - dwords = qla2x00_gid_list_size(ha) / 4; - for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS; - cnt += dwords, addr += dwords) { - if (cnt + dwords > ram_dwords) - dwords = ram_dwords - cnt; - + WRT_REG_WORD(®->mailbox0, MBC_LOAD_DUMP_MPI_RAM); WRT_REG_WORD(®->mailbox1, LSW(addr)); WRT_REG_WORD(®->mailbox8, MSW(addr)); - WRT_REG_WORD(®->mailbox2, MSW(dump_dma)); - WRT_REG_WORD(®->mailbox3, LSW(dump_dma)); + WRT_REG_WORD(®->mailbox2, MSW(LSD(dump_dma))); + WRT_REG_WORD(®->mailbox3, LSW(LSD(dump_dma))); WRT_REG_WORD(®->mailbox6, MSW(MSD(dump_dma))); WRT_REG_WORD(®->mailbox7, LSW(MSD(dump_dma))); @@ -145,76 +140,76 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); ha->flags.mbox_int = 0; - for (timer = 6000000; timer; timer--) { - /* Check for pending interrupts. */ - stat = RD_REG_DWORD(®->host_status); - if (stat & HSRX_RISC_INT) { - stat &= 0xff; - - if (stat == 0x1 || stat == 0x2 || - stat == 0x10 || stat == 0x11) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); + while (timer--) { + udelay(5); - mb0 = RD_REG_WORD(®->mailbox0); - RD_REG_WORD(®->mailbox1); + stat = RD_REG_DWORD(®->host_status); + /* Check for pending interrupts. */ + if (!(stat & HSRX_RISC_INT)) + continue; - WRT_REG_DWORD(®->hccr, - HCCRX_CLR_RISC_INT); - RD_REG_DWORD(®->hccr); - break; - } + stat &= 0xff; + if (stat != 0x1 && stat != 0x2 && + stat != 0x10 && stat != 0x11) { /* Clear this intr; it wasn't a mailbox intr */ WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD(®->hccr); + continue; } - udelay(5); + + set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + rval = RD_REG_WORD(®->mailbox0) & MBS_MASK; + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD(®->hccr); + break; } ha->flags.mbox_int = 1; + *nxt = ram + i; - if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { - rval = mb0 & MBS_MASK; - for (idx = 0; idx < dwords; idx++) - ram[cnt + idx] = IS_QLA27XX(ha) ? - le32_to_cpu(dump[idx]) : swab32(dump[idx]); - } else { - rval = QLA_FUNCTION_FAILED; + if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { + /* no interrupt, timed out*/ + return rval; + } + if (rval) { + /* error completion status */ + return rval; + } + for (j = 0; j < dwords; j++) { + ram[i + j] = + (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ? + chunk[j] : swab32(chunk[j]); } } - *nxt = rval == QLA_SUCCESS ? &ram[cnt] : NULL; - return rval; + *nxt = ram + i; + return QLA_SUCCESS; } int qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, uint32_t ram_dwords, void **nxt) { - int rval; - uint32_t cnt, stat, timer, dwords, idx; - uint16_t mb0; + int rval = QLA_FUNCTION_FAILED; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; dma_addr_t dump_dma = ha->gid_list_dma; - uint32_t *dump = (uint32_t *)ha->gid_list; + uint32_t *chunk = (void *)ha->gid_list; + uint32_t dwords = qla2x00_gid_list_size(ha) / 4; + uint32_t stat; + ulong i, j, timer = 6000000; - rval = QLA_SUCCESS; - mb0 = 0; - - WRT_REG_WORD(®->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - dwords = qla2x00_gid_list_size(ha) / 4; - for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS; - cnt += dwords, addr += dwords) { - if (cnt + dwords > ram_dwords) - dwords = ram_dwords - cnt; + for (i = 0; i < ram_dwords; i += dwords, addr += dwords) { + if (i + dwords > ram_dwords) + dwords = ram_dwords - i; + WRT_REG_WORD(®->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED); WRT_REG_WORD(®->mailbox1, LSW(addr)); WRT_REG_WORD(®->mailbox8, MSW(addr)); - WRT_REG_WORD(®->mailbox2, MSW(dump_dma)); - WRT_REG_WORD(®->mailbox3, LSW(dump_dma)); + WRT_REG_WORD(®->mailbox2, MSW(LSD(dump_dma))); + WRT_REG_WORD(®->mailbox3, LSW(LSD(dump_dma))); WRT_REG_WORD(®->mailbox6, MSW(MSD(dump_dma))); WRT_REG_WORD(®->mailbox7, LSW(MSD(dump_dma))); @@ -223,45 +218,48 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); ha->flags.mbox_int = 0; - for (timer = 6000000; timer; timer--) { - /* Check for pending interrupts. */ + while (timer--) { + udelay(5); stat = RD_REG_DWORD(®->host_status); - if (stat & HSRX_RISC_INT) { - stat &= 0xff; - if (stat == 0x1 || stat == 0x2 || - stat == 0x10 || stat == 0x11) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); - - mb0 = RD_REG_WORD(®->mailbox0); - - WRT_REG_DWORD(®->hccr, - HCCRX_CLR_RISC_INT); - RD_REG_DWORD(®->hccr); - break; - } + /* Check for pending interrupts. */ + if (!(stat & HSRX_RISC_INT)) + continue; - /* Clear this intr; it wasn't a mailbox intr */ + stat &= 0xff; + if (stat != 0x1 && stat != 0x2 && + stat != 0x10 && stat != 0x11) { WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD(®->hccr); + continue; } - udelay(5); + + set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + rval = RD_REG_WORD(®->mailbox0) & MBS_MASK; + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD(®->hccr); + break; } ha->flags.mbox_int = 1; + *nxt = ram + i; - if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { - rval = mb0 & MBS_MASK; - for (idx = 0; idx < dwords; idx++) - ram[cnt + idx] = IS_QLA27XX(ha) ? - le32_to_cpu(dump[idx]) : swab32(dump[idx]); - } else { - rval = QLA_FUNCTION_FAILED; + if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { + /* no interrupt, timed out*/ + return rval; + } + if (rval) { + /* error completion status */ + return rval; + } + for (j = 0; j < dwords; j++) { + ram[i + j] = + (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ? + chunk[j] : swab32(chunk[j]); } } - *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL; - return rval; + *nxt = ram + i; + return QLA_SUCCESS; } static int @@ -447,7 +445,7 @@ qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram, } } - *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL; + *nxt = rval == QLA_SUCCESS ? &ram[cnt] : NULL; return rval; } @@ -669,7 +667,8 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) struct qla2xxx_mq_chain *mq = ptr; device_reg_t *reg; - if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) return ptr; mq = ptr; @@ -2521,7 +2520,7 @@ qla83xx_fw_dump_failed: /****************************************************************************/ static inline int -ql_mask_match(uint32_t level) +ql_mask_match(uint level) { return (level & ql2xextended_error_logging) == level; } @@ -2540,7 +2539,7 @@ ql_mask_match(uint32_t level) * msg: The message to be displayed. */ void -ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) +ql_dbg(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...) { va_list va; struct va_format vaf; @@ -2583,8 +2582,7 @@ ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) * msg: The message to be displayed. */ void -ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, - const char *fmt, ...) +ql_dbg_pci(uint level, struct pci_dev *pdev, uint id, const char *fmt, ...) { va_list va; struct va_format vaf; @@ -2620,7 +2618,7 @@ ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, * msg: The message to be displayed. */ void -ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) +ql_log(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...) { va_list va; struct va_format vaf; @@ -2678,8 +2676,7 @@ ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) * msg: The message to be displayed. */ void -ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, - const char *fmt, ...) +ql_log_pci(uint level, struct pci_dev *pdev, uint id, const char *fmt, ...) { va_list va; struct va_format vaf; @@ -2719,7 +2716,7 @@ ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, } void -ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id) +ql_dump_regs(uint level, scsi_qla_host_t *vha, uint id) { int i; struct qla_hw_data *ha = vha->hw; @@ -2741,13 +2738,12 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id) ql_dbg(level, vha, id, "Mailbox registers:\n"); for (i = 0; i < 6; i++, mbx_reg++) ql_dbg(level, vha, id, - "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg)); + "mbox[%d] %#04x\n", i, RD_REG_WORD(mbx_reg)); } void -ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id, - uint8_t *buf, uint size) +ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, void *buf, uint size) { uint cnt; diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 8877aa97d829..bb01b680ce9f 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -318,20 +318,20 @@ struct qla2xxx_fw_dump { * as compared to other log levels. */ -extern int ql_errlev; +extern uint ql_errlev; void __attribute__((format (printf, 4, 5))) -ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); +ql_dbg(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) -ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); +ql_dbg_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) ql_dbg_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) -ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); +ql_log(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) -ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); +ql_log_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...); void __attribute__((format (printf, 4, 5))) ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3d46975a5e5c..bad2b12604f1 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -35,6 +35,7 @@ #include <scsi/scsi_bsg_fc.h> #include "qla_bsg.h" +#include "qla_dsd.h" #include "qla_nx.h" #include "qla_nx2.h" #include "qla_nvme.h" @@ -531,6 +532,8 @@ typedef struct srb { uint8_t cmd_type; uint8_t pad[3]; atomic_t ref_count; + struct kref cmd_kref; /* need to migrate ref_count over to this */ + void *priv; wait_queue_head_t nvme_ls_waitq; struct fc_port *fcport; struct scsi_qla_host *vha; @@ -545,7 +548,7 @@ typedef struct srb { u32 gen2; /* scratch */ int rc; int retry_count; - struct completion comp; + struct completion *comp; union { struct srb_iocb iocb_cmd; struct bsg_job *bsg_job; @@ -553,6 +556,7 @@ typedef struct srb { } u; void (*done)(void *, int); void (*free)(void *); + void (*put_fn)(struct kref *kref); } srb_t; #define GET_CMD_SP(sp) (sp->u.scmd.cmd) @@ -1033,6 +1037,7 @@ struct mbx_cmd_32 { #define MBC_GET_FIRMWARE_VERSION 8 /* Get firmware revision. */ #define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */ #define MBC_DUMP_RISC_RAM 0xa /* Dump RAM command. */ +#define MBC_SECURE_FLASH_UPDATE 0xa /* Secure Flash Update(28xx) */ #define MBC_LOAD_RISC_RAM_EXTENDED 0xb /* Load RAM extended. */ #define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */ #define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */ @@ -1203,6 +1208,10 @@ struct mbx_cmd_32 { #define QLA27XX_IMG_STATUS_VER_MAJOR 0x01 #define QLA27XX_IMG_STATUS_VER_MINOR 0x00 #define QLA27XX_IMG_STATUS_SIGN 0xFACEFADE +#define QLA28XX_IMG_STATUS_SIGN 0xFACEFADF +#define QLA28XX_IMG_STATUS_SIGN 0xFACEFADF +#define QLA28XX_AUX_IMG_STATUS_SIGN 0xFACEFAED +#define QLA27XX_DEFAULT_IMAGE 0 #define QLA27XX_PRIMARY_IMAGE 1 #define QLA27XX_SECONDARY_IMAGE 2 @@ -1323,8 +1332,8 @@ typedef struct { uint16_t response_q_inpointer; uint16_t request_q_length; uint16_t response_q_length; - uint32_t request_q_address[2]; - uint32_t response_q_address[2]; + __le64 request_q_address __packed; + __le64 response_q_address __packed; uint16_t lun_enables; uint8_t command_resource_count; @@ -1749,12 +1758,10 @@ typedef struct { uint16_t dseg_count; /* Data segment count. */ uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ uint32_t byte_count; /* Total byte count. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ + union { + struct dsd32 dsd32[3]; + struct dsd64 dsd64[2]; + }; } cmd_entry_t; /* @@ -1775,10 +1782,7 @@ typedef struct { uint16_t dseg_count; /* Data segment count. */ uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ uint32_t byte_count; /* Total byte count. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ + struct dsd64 dsd[2]; } cmd_a64_entry_t, request_t; /* @@ -1791,20 +1795,7 @@ typedef struct { uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ uint32_t reserved; - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ - uint32_t dseg_5_address; /* Data segment 5 address. */ - uint32_t dseg_5_length; /* Data segment 5 length. */ - uint32_t dseg_6_address; /* Data segment 6 address. */ - uint32_t dseg_6_length; /* Data segment 6 length. */ + struct dsd32 dsd[7]; } cont_entry_t; /* @@ -1816,16 +1807,7 @@ typedef struct { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address [2]; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address[2]; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address[2]; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ + struct dsd64 dsd[5]; } cont_a64_entry_t; #define PO_MODE_DIF_INSERT 0 @@ -1869,8 +1851,7 @@ struct crc_context { uint16_t reserved_2; uint16_t reserved_3; uint32_t reserved_4; - uint32_t data_address[2]; - uint32_t data_length; + struct dsd64 data_dsd; uint32_t reserved_5[2]; uint32_t reserved_6; } nobundling; @@ -1880,11 +1861,8 @@ struct crc_context { uint16_t reserved_1; __le16 dseg_count; /* Data segment count */ uint32_t reserved_2; - uint32_t data_address[2]; - uint32_t data_length; - uint32_t dif_address[2]; - uint32_t dif_length; /* Data segment 0 - * length */ + struct dsd64 data_dsd; + struct dsd64 dif_dsd; } bundling; } u; @@ -2083,10 +2061,8 @@ typedef struct { uint32_t handle2; uint32_t rsp_bytecount; uint32_t req_bytecount; - uint32_t dseg_req_address[2]; /* Data segment 0 address. */ - uint32_t dseg_req_length; /* Data segment 0 length. */ - uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */ - uint32_t dseg_rsp_length; /* Data segment 1 length. */ + struct dsd64 req_dsd; + struct dsd64 rsp_dsd; } ms_iocb_entry_t; @@ -2258,7 +2234,10 @@ typedef enum { FCT_BROADCAST, FCT_INITIATOR, FCT_TARGET, - FCT_NVME + FCT_NVME_INITIATOR = 0x10, + FCT_NVME_TARGET = 0x20, + FCT_NVME_DISCOVERY = 0x40, + FCT_NVME = 0xf0, } fc_port_type_t; enum qla_sess_deletion { @@ -2360,7 +2339,6 @@ typedef struct fc_port { unsigned int id_changed:1; unsigned int scan_needed:1; - struct work_struct nvme_del_work; struct completion nvme_del_done; uint32_t nvme_prli_service_param; #define NVME_PRLI_SP_CONF BIT_7 @@ -2463,13 +2441,7 @@ struct event_arg { #define FCS_DEVICE_LOST 3 #define FCS_ONLINE 4 -static const char * const port_state_str[] = { - "Unknown", - "UNCONFIGURED", - "DEAD", - "LOST", - "ONLINE" -}; +extern const char *const port_state_str[5]; /* * FC port flags. @@ -2672,6 +2644,7 @@ struct ct_fdmiv2_hba_attributes { #define FDMI_PORT_SPEED_8GB 0x10 #define FDMI_PORT_SPEED_16GB 0x20 #define FDMI_PORT_SPEED_32GB 0x40 +#define FDMI_PORT_SPEED_64GB 0x80 #define FDMI_PORT_SPEED_UNKNOWN 0x8000 #define FC_CLASS_2 0x04 @@ -3060,7 +3033,7 @@ struct sns_cmd_pkt { struct { uint16_t buffer_length; uint16_t reserved_1; - uint32_t buffer_address[2]; + __le64 buffer_address __packed; uint16_t subcommand_length; uint16_t reserved_2; uint16_t subcommand; @@ -3130,10 +3103,10 @@ struct rsp_que; struct isp_operations { int (*pci_config) (struct scsi_qla_host *); - void (*reset_chip) (struct scsi_qla_host *); + int (*reset_chip)(struct scsi_qla_host *); int (*chip_diag) (struct scsi_qla_host *); void (*config_rings) (struct scsi_qla_host *); - void (*reset_adapter) (struct scsi_qla_host *); + int (*reset_adapter)(struct scsi_qla_host *); int (*nvram_config) (struct scsi_qla_host *); void (*update_fw_options) (struct scsi_qla_host *); int (*load_risc) (struct scsi_qla_host *, uint32_t *); @@ -3159,9 +3132,9 @@ struct isp_operations { void *(*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t, uint32_t); - uint8_t *(*read_nvram) (struct scsi_qla_host *, uint8_t *, + uint8_t *(*read_nvram)(struct scsi_qla_host *, void *, uint32_t, uint32_t); - int (*write_nvram) (struct scsi_qla_host *, uint8_t *, uint32_t, + int (*write_nvram)(struct scsi_qla_host *, void *, uint32_t, uint32_t); void (*fw_dump) (struct scsi_qla_host *, int); @@ -3170,16 +3143,16 @@ struct isp_operations { int (*beacon_off) (struct scsi_qla_host *); void (*beacon_blink) (struct scsi_qla_host *); - uint8_t * (*read_optrom) (struct scsi_qla_host *, uint8_t *, + void *(*read_optrom)(struct scsi_qla_host *, void *, uint32_t, uint32_t); - int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t, + int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t, uint32_t); int (*get_flash_version) (struct scsi_qla_host *, void *); int (*start_scsi) (srb_t *); int (*start_scsi_mq) (srb_t *); int (*abort_isp) (struct scsi_qla_host *); - int (*iospace_config)(struct qla_hw_data*); + int (*iospace_config)(struct qla_hw_data *); int (*initialize_adapter)(struct scsi_qla_host *); }; @@ -3368,7 +3341,8 @@ struct qla_tc_param { #define QLA_MQ_SIZE 32 #define QLA_MAX_QUEUES 256 #define ISP_QUE_REG(ha, id) \ - ((ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ? \ + ((ha->mqenable || IS_QLA83XX(ha) || \ + IS_QLA27XX(ha) || IS_QLA28XX(ha)) ? \ ((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\ ((void __iomem *)ha->iobase)) #define QLA_REQ_QUE_ID(tag) \ @@ -3621,6 +3595,8 @@ struct qla_hw_data { uint32_t rida_fmt2:1; uint32_t purge_mbox:1; uint32_t n2n_bigger:1; + uint32_t secure_adapter:1; + uint32_t secure_fw:1; } flags; uint16_t max_exchg; @@ -3703,6 +3679,7 @@ struct qla_hw_data { #define PORT_SPEED_8GB 0x04 #define PORT_SPEED_16GB 0x05 #define PORT_SPEED_32GB 0x06 +#define PORT_SPEED_64GB 0x07 #define PORT_SPEED_10GB 0x13 uint16_t link_data_rate; /* F/W operating speed */ uint16_t set_data_rate; /* Set by user */ @@ -3729,6 +3706,11 @@ struct qla_hw_data { #define PCI_DEVICE_ID_QLOGIC_ISP2071 0x2071 #define PCI_DEVICE_ID_QLOGIC_ISP2271 0x2271 #define PCI_DEVICE_ID_QLOGIC_ISP2261 0x2261 +#define PCI_DEVICE_ID_QLOGIC_ISP2061 0x2061 +#define PCI_DEVICE_ID_QLOGIC_ISP2081 0x2081 +#define PCI_DEVICE_ID_QLOGIC_ISP2089 0x2089 +#define PCI_DEVICE_ID_QLOGIC_ISP2281 0x2281 +#define PCI_DEVICE_ID_QLOGIC_ISP2289 0x2289 uint32_t isp_type; #define DT_ISP2100 BIT_0 @@ -3753,7 +3735,12 @@ struct qla_hw_data { #define DT_ISP2071 BIT_19 #define DT_ISP2271 BIT_20 #define DT_ISP2261 BIT_21 -#define DT_ISP_LAST (DT_ISP2261 << 1) +#define DT_ISP2061 BIT_22 +#define DT_ISP2081 BIT_23 +#define DT_ISP2089 BIT_24 +#define DT_ISP2281 BIT_25 +#define DT_ISP2289 BIT_26 +#define DT_ISP_LAST (DT_ISP2289 << 1) uint32_t device_type; #define DT_T10_PI BIT_25 @@ -3788,6 +3775,8 @@ struct qla_hw_data { #define IS_QLA2071(ha) (DT_MASK(ha) & DT_ISP2071) #define IS_QLA2271(ha) (DT_MASK(ha) & DT_ISP2271) #define IS_QLA2261(ha) (DT_MASK(ha) & DT_ISP2261) +#define IS_QLA2081(ha) (DT_MASK(ha) & DT_ISP2081) +#define IS_QLA2281(ha) (DT_MASK(ha) & DT_ISP2281) #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ IS_QLA6312(ha) || IS_QLA6322(ha)) @@ -3797,6 +3786,7 @@ struct qla_hw_data { #define IS_QLA83XX(ha) (IS_QLA2031(ha) || IS_QLA8031(ha)) #define IS_QLA84XX(ha) (IS_QLA8432(ha)) #define IS_QLA27XX(ha) (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha)) +#define IS_QLA28XX(ha) (IS_QLA2081(ha) || IS_QLA2281(ha)) #define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ IS_QLA84XX(ha)) #define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \ @@ -3805,14 +3795,15 @@ struct qla_hw_data { #define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \ IS_QLA25XX(ha) || IS_QLA81XX(ha) || \ IS_QLA82XX(ha) || IS_QLA83XX(ha) || \ - IS_QLA8044(ha) || IS_QLA27XX(ha)) + IS_QLA8044(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \ - IS_QLA27XX(ha)) + IS_QLA27XX(ha) || IS_QLA28XX(ha)) #define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled) #define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \ - IS_QLA27XX(ha)) + IS_QLA27XX(ha) || IS_QLA28XX(ha)) #define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \ - IS_QLA27XX(ha)) + IS_QLA27XX(ha) || IS_QLA28XX(ha)) #define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha)) #define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI) @@ -3823,28 +3814,34 @@ struct qla_hw_data { #define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS) #define IS_CT6_SUPPORTED(ha) ((ha)->device_type & DT_CT6_SUPPORTED) #define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha) || \ - IS_QLA27XX(ha)) -#define IS_BIDI_CAPABLE(ha) ((IS_QLA25XX(ha) || IS_QLA2031(ha))) + IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_BIDI_CAPABLE(ha) \ + (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) /* Bit 21 of fw_attributes decides the MCTP capabilities */ #define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \ ((ha)->fw_attributes_ext[0] & BIT_0)) #define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) #define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) #define IS_PI_DIFB_DIX0_CAPABLE(ha) (0) -#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) #define IS_PI_SPLIT_DET_CAPABLE(ha) (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \ (((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22)) -#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) #define IS_TGT_MODE_CAPABLE(ha) (ha->tgt.atio_q_length) -#define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha)) -#define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) -#define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) +#define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ + IS_QLA28XX(ha)) #define IS_EXCHG_OFFLD_CAPABLE(ha) \ - (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) + (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) #define IS_EXLOGIN_OFFLD_CAPABLE(ha) \ - (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) + (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \ + IS_QLA27XX(ha) || IS_QLA28XX(ha)) #define USE_ASYNC_SCAN(ha) (IS_QLA25XX(ha) || IS_QLA81XX(ha) ||\ - IS_QLA83XX(ha) || IS_QLA27XX(ha)) + IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) /* HBA serial number */ uint8_t serial0; @@ -3888,6 +3885,9 @@ struct qla_hw_data { void *sfp_data; dma_addr_t sfp_data_dma; + void *flt; + dma_addr_t flt_dma; + #define XGMAC_DATA_SIZE 4096 void *xgmac_data; dma_addr_t xgmac_data_dma; @@ -3999,18 +3999,23 @@ struct qla_hw_data { uint8_t fw_seriallink_options[4]; uint16_t fw_seriallink_options24[4]; + uint8_t serdes_version[3]; uint8_t mpi_version[3]; uint32_t mpi_capabilities; uint8_t phy_version[3]; uint8_t pep_version[3]; /* Firmware dump template */ - void *fw_dump_template; - uint32_t fw_dump_template_len; - /* Firmware dump information. */ + struct fwdt { + void *template; + ulong length; + ulong dump_size; + } fwdt[2]; struct qla2xxx_fw_dump *fw_dump; uint32_t fw_dump_len; - int fw_dumped; + u32 fw_dump_alloc_len; + bool fw_dumped; + bool fw_dump_mpi; unsigned long fw_dump_cap_flags; #define RISC_PAUSE_CMPL 0 #define DMA_SHUTDOWN_CMPL 1 @@ -4049,7 +4054,6 @@ struct qla_hw_data { uint16_t product_id[4]; uint8_t model_number[16+1]; -#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" char model_desc[80]; uint8_t adapter_id[16+1]; @@ -4089,22 +4093,28 @@ struct qla_hw_data { uint32_t fdt_protect_sec_cmd; uint32_t fdt_wrt_sts_reg_cmd; - uint32_t flt_region_flt; - uint32_t flt_region_fdt; - uint32_t flt_region_boot; - uint32_t flt_region_boot_sec; - uint32_t flt_region_fw; - uint32_t flt_region_fw_sec; - uint32_t flt_region_vpd_nvram; - uint32_t flt_region_vpd; - uint32_t flt_region_vpd_sec; - uint32_t flt_region_nvram; - uint32_t flt_region_npiv_conf; - uint32_t flt_region_gold_fw; - uint32_t flt_region_fcp_prio; - uint32_t flt_region_bootload; - uint32_t flt_region_img_status_pri; - uint32_t flt_region_img_status_sec; + struct { + uint32_t flt_region_flt; + uint32_t flt_region_fdt; + uint32_t flt_region_boot; + uint32_t flt_region_boot_sec; + uint32_t flt_region_fw; + uint32_t flt_region_fw_sec; + uint32_t flt_region_vpd_nvram; + uint32_t flt_region_vpd_nvram_sec; + uint32_t flt_region_vpd; + uint32_t flt_region_vpd_sec; + uint32_t flt_region_nvram; + uint32_t flt_region_nvram_sec; + uint32_t flt_region_npiv_conf; + uint32_t flt_region_gold_fw; + uint32_t flt_region_fcp_prio; + uint32_t flt_region_bootload; + uint32_t flt_region_img_status_pri; + uint32_t flt_region_img_status_sec; + uint32_t flt_region_aux_img_status_pri; + uint32_t flt_region_aux_img_status_sec; + }; uint8_t active_image; /* Needed for BEACON */ @@ -4197,8 +4207,8 @@ struct qla_hw_data { struct qlt_hw_data tgt; int allow_cna_fw_dump; uint32_t fw_ability_mask; - uint16_t min_link_speed; - uint16_t max_speed_sup; + uint16_t min_supported_speed; + uint16_t max_supported_speed; /* DMA pool for the DIF bundling buffers */ struct dma_pool *dif_bundl_pool; @@ -4225,9 +4235,20 @@ struct qla_hw_data { atomic_t zio_threshold; uint16_t last_zio_threshold; + #define DEFAULT_ZIO_THRESHOLD 5 }; +struct active_regions { + uint8_t global; + struct { + uint8_t board_config; + uint8_t vpd_nvram; + uint8_t npiv_config_0_1; + uint8_t npiv_config_2_3; + } aux; +}; + #define FW_ABILITY_MAX_SPEED_MASK 0xFUL #define FW_ABILITY_MAX_SPEED_16G 0x0 #define FW_ABILITY_MAX_SPEED_32G 0x1 @@ -4315,6 +4336,7 @@ typedef struct scsi_qla_host { #define N2N_LOGIN_NEEDED 30 #define IOCB_WORK_ACTIVE 31 #define SET_ZIO_THRESHOLD_NEEDED 32 +#define ISP_ABORT_TO_ROM 33 unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ @@ -4356,7 +4378,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; uint16_t fcoe_vlan_id; uint16_t fcoe_fcf_idx; @@ -4429,7 +4450,7 @@ typedef struct scsi_qla_host { int fcport_count; wait_queue_head_t fcport_waitQ; wait_queue_head_t vref_waitq; - uint8_t min_link_speed_feat; + uint8_t min_supported_speed; uint8_t n2n_node_name[WWN_SIZE]; uint8_t n2n_port_name[WWN_SIZE]; uint16_t n2n_id; @@ -4441,14 +4462,21 @@ typedef struct scsi_qla_host { struct qla27xx_image_status { uint8_t image_status_mask; - uint16_t generation_number; - uint8_t reserved[3]; - uint8_t ver_minor; + uint16_t generation; uint8_t ver_major; + uint8_t ver_minor; + uint8_t bitmap; /* 28xx only */ + uint8_t reserved[2]; uint32_t checksum; uint32_t signature; } __packed; +/* 28xx aux image status bimap values */ +#define QLA28XX_AUX_IMG_BOARD_CONFIG BIT_0 +#define QLA28XX_AUX_IMG_VPD_NVRAM BIT_1 +#define QLA28XX_AUX_IMG_NPIV_CONFIG_0_1 BIT_2 +#define QLA28XX_AUX_IMG_NPIV_CONFIG_2_3 BIT_3 + #define SET_VP_IDX 1 #define SET_AL_PA 2 #define RESET_VP_IDX 3 @@ -4495,6 +4523,24 @@ struct qla2_sgx { } \ } + +#define SFUB_CHECKSUM_SIZE 4 + +struct secure_flash_update_block { + uint32_t block_info; + uint32_t signature_lo; + uint32_t signature_hi; + uint32_t signature_upper[0x3e]; +}; + +struct secure_flash_update_block_pk { + uint32_t block_info; + uint32_t signature_lo; + uint32_t signature_hi; + uint32_t signature_upper[0x3e]; + uint32_t public_key[0x41]; +}; + /* * Macros to help code, maintain, etc. */ @@ -4595,6 +4641,7 @@ struct qla2_sgx { #define OPTROM_SIZE_81XX 0x400000 #define OPTROM_SIZE_82XX 0x800000 #define OPTROM_SIZE_83XX 0x1000000 +#define OPTROM_SIZE_28XX 0x2000000 #define OPTROM_BURST_SIZE 0x1000 #define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) @@ -4691,10 +4738,13 @@ struct sff_8247_a0 { #define AUTO_DETECT_SFP_SUPPORT(_vha)\ (ql2xautodetectsfp && !_vha->vp_idx && \ (IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\ - IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw))) + IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \ + IS_QLA28XX(_vha->hw))) + +#define FLASH_SEMAPHORE_REGISTER_ADDR 0x00101016 #define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \ - (IS_QLA27XX(_ha) || IS_QLA83XX(_ha))) + (IS_QLA27XX(_ha) || IS_QLA28XX(_ha) || IS_QLA83XX(_ha))) #define SAVE_TOPO(_ha) { \ if (_ha->current_topology) \ diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 5819a45ac5ef..a432caebefec 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -41,6 +41,7 @@ static int qla2x00_dfs_tgt_sess_open(struct inode *inode, struct file *file) { scsi_qla_host_t *vha = inode->i_private; + return single_open(file, qla2x00_dfs_tgt_sess_show, vha); } @@ -161,6 +162,7 @@ static int qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file) { struct scsi_qla_host *vha = inode->i_private; + return single_open(file, qla_dfs_fw_resource_cnt_show, vha); } @@ -250,6 +252,7 @@ static int qla_dfs_tgt_counters_open(struct inode *inode, struct file *file) { struct scsi_qla_host *vha = inode->i_private; + return single_open(file, qla_dfs_tgt_counters_show, vha); } @@ -386,7 +389,7 @@ qla_dfs_naqp_write(struct file *file, const char __user *buffer, int rc = 0; unsigned long num_act_qp; - if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha))) { + if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))) { pr_err("host%ld: this adapter does not support Multi Q.", vha->host_no); return -EINVAL; @@ -438,7 +441,7 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) goto out; if (!ha->fce) goto out; @@ -474,7 +477,7 @@ create_nodes: ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess", S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops); - if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) + if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) ha->tgt.dfs_naqp = debugfs_create_file("naqp", 0400, ha->dfs_dir, vha, &dfs_naqp_ops); out: diff --git a/drivers/scsi/qla2xxx/qla_dsd.h b/drivers/scsi/qla2xxx/qla_dsd.h new file mode 100644 index 000000000000..7479924ba422 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_dsd.h @@ -0,0 +1,30 @@ +#ifndef _QLA_DSD_H_ +#define _QLA_DSD_H_ + +/* 32-bit data segment descriptor (8 bytes) */ +struct dsd32 { + __le32 address; + __le32 length; +}; + +static inline void append_dsd32(struct dsd32 **dsd, struct scatterlist *sg) +{ + put_unaligned_le32(sg_dma_address(sg), &(*dsd)->address); + put_unaligned_le32(sg_dma_len(sg), &(*dsd)->length); + (*dsd)++; +} + +/* 64-bit data segment descriptor (12 bytes) */ +struct dsd64 { + __le64 address; + __le32 length; +} __packed; + +static inline void append_dsd64(struct dsd64 **dsd, struct scatterlist *sg) +{ + put_unaligned_le64(sg_dma_address(sg), &(*dsd)->address); + put_unaligned_le32(sg_dma_len(sg), &(*dsd)->length); + (*dsd)++; +} + +#endif diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 50c1e6c62e31..df079a8c2b33 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -10,6 +10,8 @@ #include <linux/nvme.h> #include <linux/nvme-fc.h> +#include "qla_dsd.h" + #define MBS_CHECKSUM_ERROR 0x4010 #define MBS_INVALID_PRODUCT_KEY 0x4020 @@ -339,9 +341,9 @@ struct init_cb_24xx { uint16_t prio_request_q_length; - uint32_t request_q_address[2]; - uint32_t response_q_address[2]; - uint32_t prio_request_q_address[2]; + __le64 request_q_address __packed; + __le64 response_q_address __packed; + __le64 prio_request_q_address __packed; uint16_t msix; uint16_t msix_atio; @@ -349,7 +351,7 @@ struct init_cb_24xx { uint16_t atio_q_inpointer; uint16_t atio_q_length; - uint32_t atio_q_address[2]; + __le64 atio_q_address __packed; uint16_t interrupt_delay_timer; /* 100us increments. */ uint16_t login_timeout; @@ -453,7 +455,7 @@ struct cmd_bidir { #define BD_WRITE_DATA BIT_0 uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ - uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */ + __le64 fcp_cmnd_dseg_address __packed;/* Data segment address. */ uint16_t reserved[2]; /* Reserved */ @@ -463,8 +465,7 @@ struct cmd_bidir { uint8_t port_id[3]; /* PortID of destination port.*/ uint8_t vp_index; - uint32_t fcp_data_dseg_address[2]; /* Data segment address. */ - uint16_t fcp_data_dseg_len; /* Data segment length. */ + struct dsd64 fcp_dsd; }; #define COMMAND_TYPE_6 0x48 /* Command Type 6 entry */ @@ -491,18 +492,18 @@ struct cmd_type_6 { #define CF_READ_DATA BIT_1 #define CF_WRITE_DATA BIT_0 - uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ - uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */ - - uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */ + uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ + /* Data segment address. */ + __le64 fcp_cmnd_dseg_address __packed; + /* Data segment address. */ + __le64 fcp_rsp_dseg_address __packed; uint32_t byte_count; /* Total byte count. */ uint8_t port_id[3]; /* PortID of destination port. */ uint8_t vp_index; - uint32_t fcp_data_dseg_address[2]; /* Data segment address. */ - uint32_t fcp_data_dseg_len; /* Data segment length. */ + struct dsd64 fcp_dsd; }; #define COMMAND_TYPE_7 0x18 /* Command Type 7 entry */ @@ -548,8 +549,7 @@ struct cmd_type_7 { uint8_t port_id[3]; /* PortID of destination port. */ uint8_t vp_index; - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_len; /* Data segment 0 length. */ + struct dsd64 dsd; }; #define COMMAND_TYPE_CRC_2 0x6A /* Command Type CRC_2 (Type 6) @@ -573,17 +573,17 @@ struct cmd_type_crc_2 { uint16_t control_flags; /* Control flags. */ - uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ - uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */ - - uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */ + uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ + __le64 fcp_cmnd_dseg_address __packed; + /* Data segment address. */ + __le64 fcp_rsp_dseg_address __packed; uint32_t byte_count; /* Total byte count. */ uint8_t port_id[3]; /* PortID of destination port. */ uint8_t vp_index; - uint32_t crc_context_address[2]; /* Data segment address. */ + __le64 crc_context_address __packed; /* Data segment address. */ uint16_t crc_context_len; /* Data segment length. */ uint16_t reserved_1; /* MUST be set to 0. */ }; @@ -717,10 +717,7 @@ struct ct_entry_24xx { uint32_t rsp_byte_count; uint32_t cmd_byte_count; - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_len; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_len; /* Data segment 1 length. */ + struct dsd64 dsd[2]; }; /* @@ -767,9 +764,9 @@ struct els_entry_24xx { uint32_t rx_byte_count; uint32_t tx_byte_count; - uint32_t tx_address[2]; /* Data segment 0 address. */ + __le64 tx_address __packed; /* Data segment 0 address. */ uint32_t tx_len; /* Data segment 0 length. */ - uint32_t rx_address[2]; /* Data segment 1 address. */ + __le64 rx_address __packed; /* Data segment 1 address. */ uint32_t rx_len; /* Data segment 1 length. */ }; @@ -1422,9 +1419,9 @@ struct vf_evfp_entry_24xx { uint16_t control_flags; uint32_t io_parameter_0; uint32_t io_parameter_1; - uint32_t tx_address[2]; /* Data segment 0 address. */ + __le64 tx_address __packed; /* Data segment 0 address. */ uint32_t tx_len; /* Data segment 0 length. */ - uint32_t rx_address[2]; /* Data segment 1 address. */ + __le64 rx_address __packed; /* Data segment 1 address. */ uint32_t rx_len; /* Data segment 1 length. */ }; @@ -1515,13 +1512,31 @@ struct qla_flt_header { #define FLT_REG_VPD_SEC_27XX_2 0xD8 #define FLT_REG_VPD_SEC_27XX_3 0xDA +/* 28xx */ +#define FLT_REG_AUX_IMG_PRI_28XX 0x125 +#define FLT_REG_AUX_IMG_SEC_28XX 0x126 +#define FLT_REG_VPD_SEC_28XX_0 0x10C +#define FLT_REG_VPD_SEC_28XX_1 0x10E +#define FLT_REG_VPD_SEC_28XX_2 0x110 +#define FLT_REG_VPD_SEC_28XX_3 0x112 +#define FLT_REG_NVRAM_SEC_28XX_0 0x10D +#define FLT_REG_NVRAM_SEC_28XX_1 0x10F +#define FLT_REG_NVRAM_SEC_28XX_2 0x111 +#define FLT_REG_NVRAM_SEC_28XX_3 0x113 + struct qla_flt_region { - uint32_t code; + uint16_t code; + uint8_t attribute; + uint8_t reserved; uint32_t size; uint32_t start; uint32_t end; }; +#define FLT_REGION_SIZE 16 +#define FLT_MAX_REGIONS 0xFF +#define FLT_REGIONS_SIZE (FLT_REGION_SIZE * FLT_MAX_REGIONS) + /* Flash NPIV Configuration Table ********************************************/ struct qla_npiv_header { @@ -1588,8 +1603,7 @@ struct verify_chip_entry_84xx { uint32_t fw_seq_size; uint32_t relative_offset; - uint32_t dseg_address[2]; - uint32_t dseg_length; + struct dsd64 dsd; }; struct verify_chip_rsp_84xx { @@ -1646,8 +1660,7 @@ struct access_chip_84xx { uint32_t total_byte_cnt; uint32_t reserved4; - uint32_t dseg_address[2]; - uint32_t dseg_length; + struct dsd64 dsd; }; struct access_chip_rsp_84xx { @@ -1711,6 +1724,10 @@ struct access_chip_rsp_84xx { #define LR_DIST_FW_SHIFT (LR_DIST_FW_POS - LR_DIST_NV_POS) #define LR_DIST_FW_FIELD(x) ((x) << LR_DIST_FW_SHIFT & 0xf000) +/* FAC semaphore defines */ +#define FAC_SEMAPHORE_UNLOCK 0 +#define FAC_SEMAPHORE_LOCK 1 + struct nvram_81xx { /* NVRAM header. */ uint8_t id[4]; @@ -1757,7 +1774,7 @@ struct nvram_81xx { uint16_t reserved_6_3[14]; /* Offset 192. */ - uint8_t min_link_speed; + uint8_t min_supported_speed; uint8_t reserved_7_0; uint16_t reserved_7[31]; @@ -1911,15 +1928,15 @@ struct init_cb_81xx { uint16_t prio_request_q_length; - uint32_t request_q_address[2]; - uint32_t response_q_address[2]; - uint32_t prio_request_q_address[2]; + __le64 request_q_address __packed; + __le64 response_q_address __packed; + __le64 prio_request_q_address __packed; uint8_t reserved_4[8]; uint16_t atio_q_inpointer; uint16_t atio_q_length; - uint32_t atio_q_address[2]; + __le64 atio_q_address __packed; uint16_t interrupt_delay_timer; /* 100us increments. */ uint16_t login_timeout; @@ -2005,6 +2022,8 @@ struct ex_init_cb_81xx { #define FARX_ACCESS_FLASH_CONF_81XX 0x7FFD0000 #define FARX_ACCESS_FLASH_DATA_81XX 0x7F800000 +#define FARX_ACCESS_FLASH_CONF_28XX 0x7FFD0000 +#define FARX_ACCESS_FLASH_DATA_28XX 0x7F7D0000 /* FCP priority config defines *************************************/ /* operations */ @@ -2079,6 +2098,7 @@ struct qla_fcp_prio_cfg { #define FA_NPIV_CONF1_ADDR_81 0xD2000 /* 83XX Flash locations -- occupies second 8MB region. */ -#define FA_FLASH_LAYOUT_ADDR_83 0xFC400 +#define FA_FLASH_LAYOUT_ADDR_83 (0x3F1000/4) +#define FA_FLASH_LAYOUT_ADDR_28 (0x11000/4) #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 4eefe69ca807..f9669fdf7798 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -18,14 +18,14 @@ extern int qla2100_pci_config(struct scsi_qla_host *); extern int qla2300_pci_config(struct scsi_qla_host *); extern int qla24xx_pci_config(scsi_qla_host_t *); extern int qla25xx_pci_config(scsi_qla_host_t *); -extern void qla2x00_reset_chip(struct scsi_qla_host *); -extern void qla24xx_reset_chip(struct scsi_qla_host *); +extern int qla2x00_reset_chip(struct scsi_qla_host *); +extern int qla24xx_reset_chip(struct scsi_qla_host *); extern int qla2x00_chip_diag(struct scsi_qla_host *); extern int qla24xx_chip_diag(struct scsi_qla_host *); extern void qla2x00_config_rings(struct scsi_qla_host *); extern void qla24xx_config_rings(struct scsi_qla_host *); -extern void qla2x00_reset_adapter(struct scsi_qla_host *); -extern void qla24xx_reset_adapter(struct scsi_qla_host *); +extern int qla2x00_reset_adapter(struct scsi_qla_host *); +extern int qla24xx_reset_adapter(struct scsi_qla_host *); extern int qla2x00_nvram_config(struct scsi_qla_host *); extern int qla24xx_nvram_config(struct scsi_qla_host *); extern int qla81xx_nvram_config(struct scsi_qla_host *); @@ -38,8 +38,7 @@ extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); extern int qla2x00_perform_loop_resync(scsi_qla_host_t *); extern int qla2x00_loop_resync(scsi_qla_host_t *); - -extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); +extern void qla2x00_clear_loop_id(fc_port_t *fcport); extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); @@ -80,6 +79,7 @@ int qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e); extern void *qla2x00_alloc_iocbs_ready(struct qla_qpair *, srb_t *); extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *); +extern void qla2x00_set_fcport_state(fc_port_t *fcport, int state); extern fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); @@ -93,7 +93,6 @@ extern int qla2xxx_mctp_dump(scsi_qla_host_t *); extern int qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *); extern int qla2x00_init_rings(scsi_qla_host_t *); -extern uint8_t qla27xx_find_valid_image(struct scsi_qla_host *); extern struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *, int, int, bool); extern int qla2xxx_delete_qpair(struct scsi_qla_host *, struct qla_qpair *); @@ -108,6 +107,11 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *); int qla24xx_detect_sfp(scsi_qla_host_t *vha); int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); +extern void qla28xx_get_aux_images(struct scsi_qla_host *, + struct active_regions *); +extern void qla27xx_get_active_image(struct scsi_qla_host *, + struct active_regions *); + void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *, @@ -118,6 +122,7 @@ int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport); void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport); int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *); void qla_rscn_replay(fc_port_t *fcport); +extern bool qla24xx_risc_firmware_invalid(uint32_t *); /* * Global Data in qla_os.c source file. @@ -215,7 +220,6 @@ extern void qla24xx_sched_upd_fcport(fc_port_t *); void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, uint16_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); -int qla24xx_async_abort_cmd(srb_t *, bool); int qla24xx_post_relogin_work(struct scsi_qla_host *vha); void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); @@ -238,7 +242,7 @@ extern void qla24xx_report_id_acquisition(scsi_qla_host_t *, struct vp_rpt_id_entry_24xx *); extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *); -extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *); +extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *); extern void qla2x00_sp_free_dma(void *); extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *); @@ -276,21 +280,20 @@ extern int qla2x00_start_sp(srb_t *); extern int qla24xx_dif_start_scsi(srb_t *); extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t); extern int qla2xxx_dif_start_scsi_mq(srb_t *); +extern void qla2x00_init_timer(srb_t *sp, unsigned long tmo); extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *); extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *); extern void *__qla2x00_alloc_iocbs(struct qla_qpair *, srb_t *); extern int qla2x00_issue_marker(scsi_qla_host_t *, int); extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *, - uint32_t *, uint16_t, struct qla_tc_param *); + struct dsd64 *, uint16_t, struct qla_tc_param *); extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *, - uint32_t *, uint16_t, struct qla_tc_param *); + struct dsd64 *, uint16_t, struct qla_tc_param *); extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *, - uint32_t *, uint16_t, struct qla_tgt_cmd *); + struct dsd64 *, uint16_t, struct qla_tgt_cmd *); extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *); extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *); -extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *, - struct cmd_type_crc_2 *, uint16_t, uint16_t, uint16_t); /* * Global Function Prototypes in qla_mbx.c source file. @@ -466,6 +469,8 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int); extern int qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t); +extern int qla81xx_fac_semaphore_access(scsi_qla_host_t *, int); + extern int qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *); @@ -511,6 +516,14 @@ extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *); extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t); int qla24xx_res_count_wait(struct scsi_qla_host *, uint16_t *, int); +extern int qla28xx_secure_flash_update(scsi_qla_host_t *, uint16_t, uint16_t, + uint32_t, dma_addr_t, uint32_t); + +extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t, + uint32_t *); +extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t, + uint32_t); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -542,19 +555,20 @@ fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8); */ extern void qla2x00_release_nvram_protection(scsi_qla_host_t *); extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *, - uint32_t, uint32_t); -extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); + uint32_t, uint32_t); +extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, void *, uint32_t, + uint32_t); +extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, void *, uint32_t, + uint32_t); +extern int qla2x00_write_nvram_data(scsi_qla_host_t *, void *, uint32_t, + uint32_t); +extern int qla24xx_write_nvram_data(scsi_qla_host_t *, void *, uint32_t, + uint32_t); +extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, void *, uint32_t, + uint32_t); +extern int qla25xx_write_nvram_data(scsi_qla_host_t *, void *, uint32_t, + uint32_t); + extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t); bool qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *, uint32_t); bool qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *, uint16_t); @@ -574,18 +588,18 @@ extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *); extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t, uint32_t, uint16_t *); -extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *, +extern void *qla2x00_read_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); -extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *, +extern int qla2x00_write_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); -extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, +extern void *qla24xx_read_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); -extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, +extern int qla24xx_write_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); -extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, +extern void *qla25xx_read_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); -extern uint8_t *qla8044_read_optrom_data(struct scsi_qla_host *, - uint8_t *, uint32_t, uint32_t); +extern void *qla8044_read_optrom_data(struct scsi_qla_host *, + void *, uint32_t, uint32_t); extern void qla8044_watchdog(struct scsi_qla_host *vha); extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); @@ -610,20 +624,13 @@ extern void qla82xx_fw_dump(scsi_qla_host_t *, int); extern void qla8044_fw_dump(scsi_qla_host_t *, int); extern void qla27xx_fwdump(scsi_qla_host_t *, int); -extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *); +extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *, void *); extern int qla27xx_fwdt_template_valid(void *); extern ulong qla27xx_fwdt_template_size(void *); -extern const void *qla27xx_fwdt_template_default(void); -extern ulong qla27xx_fwdt_template_default_size(void); - -extern void qla2x00_dump_regs(scsi_qla_host_t *); -extern void qla2x00_dump_buffer(uint8_t *, uint32_t); -extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t); -extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t); -extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t, - uint8_t *, uint32_t); -extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int); +extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int); +extern void ql_dump_regs(uint, scsi_qla_host_t *, uint); +extern void ql_dump_buffer(uint, scsi_qla_host_t *, uint, void *, uint); /* * Global Function Prototypes in qla_gs.c source file. */ @@ -722,7 +729,7 @@ extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); /* qlafx00 related functions */ extern int qlafx00_pci_config(struct scsi_qla_host *); extern int qlafx00_initialize_adapter(struct scsi_qla_host *); -extern void qlafx00_soft_reset(scsi_qla_host_t *); +extern int qlafx00_soft_reset(scsi_qla_host_t *); extern int qlafx00_chip_diag(scsi_qla_host_t *); extern void qlafx00_config_rings(struct scsi_qla_host *); extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *); @@ -765,16 +772,16 @@ extern int qla82xx_pci_region_offset(struct pci_dev *, int); extern int qla82xx_iospace_config(struct qla_hw_data *); /* Initialization related functions */ -extern void qla82xx_reset_chip(struct scsi_qla_host *); +extern int qla82xx_reset_chip(struct scsi_qla_host *); extern void qla82xx_config_rings(struct scsi_qla_host *); extern void qla82xx_watchdog(scsi_qla_host_t *); extern int qla82xx_start_firmware(scsi_qla_host_t *); /* Firmware and flash related functions */ extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); -extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, +extern void *qla82xx_read_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); -extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, +extern int qla82xx_write_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); /* Mailbox related functions */ @@ -870,7 +877,7 @@ extern void qla8044_clear_drv_active(struct qla_hw_data *); void qla8044_get_minidump(struct scsi_qla_host *vha); int qla8044_collect_md_data(struct scsi_qla_host *vha); extern int qla8044_md_get_template(scsi_qla_host_t *); -extern int qla8044_write_optrom_data(struct scsi_qla_host *, uint8_t *, +extern int qla8044_write_optrom_data(struct scsi_qla_host *, void *, uint32_t, uint32_t); extern irqreturn_t qla8044_intr_handler(int, void *); extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t); @@ -901,4 +908,6 @@ void qlt_clr_qp_table(struct scsi_qla_host *vha); void qlt_set_mode(struct scsi_qla_host *); int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode); +/* nvme.c */ +void qla_nvme_unregister_remote_port(struct fc_port *fcport); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index c6fdad12428e..9f58e591666d 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -45,13 +45,11 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) ms_pkt->rsp_bytecount = cpu_to_le32(arg->rsp_size); ms_pkt->req_bytecount = cpu_to_le32(arg->req_size); - ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(arg->req_dma)); - ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(arg->req_dma)); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + put_unaligned_le64(arg->req_dma, &ms_pkt->req_dsd.address); + ms_pkt->req_dsd.length = ms_pkt->req_bytecount; - ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(arg->rsp_dma)); - ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(arg->rsp_dma)); - ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; + put_unaligned_le64(arg->rsp_dma, &ms_pkt->rsp_dsd.address); + ms_pkt->rsp_dsd.length = ms_pkt->rsp_bytecount; vha->qla_stats.control_requests++; @@ -83,13 +81,11 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size); ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size); - ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(arg->req_dma)); - ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(arg->req_dma)); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + put_unaligned_le64(arg->req_dma, &ct_pkt->dsd[0].address); + ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count; - ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(arg->rsp_dma)); - ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(arg->rsp_dma)); - ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + put_unaligned_le64(arg->rsp_dma, &ct_pkt->dsd[1].address); + ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count; ct_pkt->vp_index = vha->vp_idx; vha->qla_stats.control_requests++; @@ -152,8 +148,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, vha->d_id.b.area, vha->d_id.b.al_pa, comp_status, ct_rsp->header.response); ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, - 0x2078, (uint8_t *)&ct_rsp->header, - sizeof(struct ct_rsp_hdr)); + 0x2078, ct_rsp, + offsetof(typeof(*ct_rsp), rsp)); rval = QLA_INVALID_COMMAND; } else rval = QLA_SUCCESS; @@ -1000,8 +996,7 @@ qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len, memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt)); wc = data_size / 2; /* Size in 16bit words. */ sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc); - sns_cmd->p.cmd.buffer_address[0] = cpu_to_le32(LSD(ha->sns_cmd_dma)); - sns_cmd->p.cmd.buffer_address[1] = cpu_to_le32(MSD(ha->sns_cmd_dma)); + put_unaligned_le64(ha->sns_cmd_dma, &sns_cmd->p.cmd.buffer_address); sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len); sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd); wc = (data_size - 16) / 4; /* Size in 32bit words. */ @@ -1385,6 +1380,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha) int ret, rval; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct qla_hw_data *ha = vha->hw; + ret = QLA_SUCCESS; if (vha->flags.management_server_logged_in) return ret; @@ -1423,6 +1419,7 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, { ms_iocb_entry_t *ms_pkt; struct qla_hw_data *ha = vha->hw; + ms_pkt = ha->ms_iocb; memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); @@ -1436,13 +1433,11 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); ms_pkt->req_bytecount = cpu_to_le32(req_size); - ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + put_unaligned_le64(ha->ct_sns_dma, &ms_pkt->req_dsd.address); + ms_pkt->req_dsd.length = ms_pkt->req_bytecount; - ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; + put_unaligned_le64(ha->ct_sns_dma, &ms_pkt->rsp_dsd.address); + ms_pkt->rsp_dsd.length = ms_pkt->rsp_bytecount; return ms_pkt; } @@ -1474,13 +1469,11 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); ct_pkt->cmd_byte_count = cpu_to_le32(req_size); - ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[0].address); + ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count; - ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[1].address); + ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count; ct_pkt->vp_index = vha->vp_idx; return ct_pkt; @@ -1495,10 +1488,10 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size) if (IS_FWI2_CAPABLE(ha)) { ct_pkt->cmd_byte_count = cpu_to_le32(req_size); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count; } else { ms_pkt->req_bytecount = cpu_to_le32(req_size); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + ms_pkt->req_dsd.length = ms_pkt->req_bytecount; } return ms_pkt; @@ -1794,7 +1787,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) if (IS_CNA_CAPABLE(ha)) eiter->a.sup_speed = cpu_to_be32( FDMI_PORT_SPEED_10GB); - else if (IS_QLA27XX(ha)) + else if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) eiter->a.sup_speed = cpu_to_be32( FDMI_PORT_SPEED_32GB| FDMI_PORT_SPEED_16GB| @@ -2373,7 +2366,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) if (IS_CNA_CAPABLE(ha)) eiter->a.sup_speed = cpu_to_be32( FDMI_PORT_SPEED_10GB); - else if (IS_QLA27XX(ha)) + else if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) eiter->a.sup_speed = cpu_to_be32( FDMI_PORT_SPEED_32GB| FDMI_PORT_SPEED_16GB| @@ -2446,7 +2439,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); eiter->len = cpu_to_be16(4 + 4); eiter->a.max_frame_size = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size): + le16_to_cpu(icb24->frame_payload_size) : le16_to_cpu(ha->init_cb->frame_payload_size); eiter->a.max_frame_size = cpu_to_be32(eiter->a.max_frame_size); size += 4 + 4; @@ -2783,6 +2776,31 @@ qla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd, return &p->p.req; } +static uint16_t +qla2x00_port_speed_capability(uint16_t speed) +{ + switch (speed) { + case BIT_15: + return PORT_SPEED_1GB; + case BIT_14: + return PORT_SPEED_2GB; + case BIT_13: + return PORT_SPEED_4GB; + case BIT_12: + return PORT_SPEED_10GB; + case BIT_11: + return PORT_SPEED_8GB; + case BIT_10: + return PORT_SPEED_16GB; + case BIT_8: + return PORT_SPEED_32GB; + case BIT_7: + return PORT_SPEED_64GB; + default: + return PORT_SPEED_UNKNOWN; + } +} + /** * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. * @vha: HA context @@ -2855,31 +2873,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) } rval = QLA_FUNCTION_FAILED; } else { - /* Save port-speed */ - switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) { - case BIT_15: - list[i].fp_speed = PORT_SPEED_1GB; - break; - case BIT_14: - list[i].fp_speed = PORT_SPEED_2GB; - break; - case BIT_13: - list[i].fp_speed = PORT_SPEED_4GB; - break; - case BIT_12: - list[i].fp_speed = PORT_SPEED_10GB; - break; - case BIT_11: - list[i].fp_speed = PORT_SPEED_8GB; - break; - case BIT_10: - list[i].fp_speed = PORT_SPEED_16GB; - break; - case BIT_8: - list[i].fp_speed = PORT_SPEED_32GB; - break; - } - + list->fp_speed = qla2x00_port_speed_capability( + be16_to_cpu(ct_rsp->rsp.gpsc.speed)); ql_dbg(ql_dbg_disc, vha, 0x205b, "GPSC ext entry - fpn " "%8phN speeds=%04x speed=%04x.\n", @@ -3031,6 +3026,8 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) "Async done-%s res %x, WWPN %8phC \n", sp->name, res, fcport->port_name); + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + if (res == QLA_FUNCTION_TIMEOUT) return; @@ -3048,29 +3045,8 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) goto done; } } else { - switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) { - case BIT_15: - fcport->fp_speed = PORT_SPEED_1GB; - break; - case BIT_14: - fcport->fp_speed = PORT_SPEED_2GB; - break; - case BIT_13: - fcport->fp_speed = PORT_SPEED_4GB; - break; - case BIT_12: - fcport->fp_speed = PORT_SPEED_10GB; - break; - case BIT_11: - fcport->fp_speed = PORT_SPEED_8GB; - break; - case BIT_10: - fcport->fp_speed = PORT_SPEED_16GB; - break; - case BIT_8: - fcport->fp_speed = PORT_SPEED_32GB; - break; - } + fcport->fp_speed = qla2x00_port_speed_capability( + be16_to_cpu(ct_rsp->rsp.gpsc.speed)); ql_dbg(ql_dbg_disc, vha, 0x2054, "Async-%s OUT WWPN %8phC speeds=%04x speed=%04x.\n", @@ -4370,6 +4346,7 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport) done_free_sp: sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; done: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0c700b140ce7..4059655639d9 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -95,6 +95,79 @@ qla2x00_get_async_timeout(struct scsi_qla_host *vha) return tmo; } +static void qla24xx_abort_iocb_timeout(void *data) +{ + srb_t *sp = data; + struct srb_iocb *abt = &sp->u.iocb_cmd; + + abt->u.abt.comp_status = CS_TIMEOUT; + sp->done(sp, QLA_FUNCTION_TIMEOUT); +} + +static void qla24xx_abort_sp_done(void *ptr, int res) +{ + srb_t *sp = ptr; + struct srb_iocb *abt = &sp->u.iocb_cmd; + + if (del_timer(&sp->u.iocb_cmd.timer)) { + if (sp->flags & SRB_WAKEUP_ON_COMP) + complete(&abt->u.abt.comp); + else + sp->free(sp); + } +} + +static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) +{ + scsi_qla_host_t *vha = cmd_sp->vha; + struct srb_iocb *abt_iocb; + srb_t *sp; + int rval = QLA_FUNCTION_FAILED; + + sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, + GFP_ATOMIC); + if (!sp) + goto done; + + abt_iocb = &sp->u.iocb_cmd; + sp->type = SRB_ABT_CMD; + sp->name = "abort"; + sp->qpair = cmd_sp->qpair; + if (wait) + sp->flags = SRB_WAKEUP_ON_COMP; + + abt_iocb->timeout = qla24xx_abort_iocb_timeout; + init_completion(&abt_iocb->u.abt.comp); + /* FW can send 2 x ABTS's timeout/20s */ + qla2x00_init_timer(sp, 42); + + abt_iocb->u.abt.cmd_hndl = cmd_sp->handle; + abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id); + + sp->done = qla24xx_abort_sp_done; + + ql_dbg(ql_dbg_async, vha, 0x507c, + "Abort command issued - hdl=%x, type=%x\n", cmd_sp->handle, + cmd_sp->type); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + if (wait) { + wait_for_completion(&abt_iocb->u.abt.comp); + rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? + QLA_SUCCESS : QLA_FUNCTION_FAILED; + } else { + goto done; + } + +done_free_sp: + sp->free(sp); +done: + return rval; +} + void qla2x00_async_iocb_timeout(void *data) { @@ -514,6 +587,72 @@ done: return rval; } +static bool qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id) +{ + struct qla_hw_data *ha = vha->hw; + + if (IS_FWI2_CAPABLE(ha)) + return loop_id > NPH_LAST_HANDLE; + + return (loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) || + loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST; +} + +/** + * qla2x00_find_new_loop_id - scan through our port list and find a new usable loop ID + * @vha: adapter state pointer. + * @dev: port structure pointer. + * + * Returns: + * qla2x00 local function return status code. + * + * Context: + * Kernel context. + */ +static int qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) +{ + int rval; + struct qla_hw_data *ha = vha->hw; + unsigned long flags = 0; + + rval = QLA_SUCCESS; + + spin_lock_irqsave(&ha->vport_slock, flags); + + dev->loop_id = find_first_zero_bit(ha->loop_id_map, LOOPID_MAP_SIZE); + if (dev->loop_id >= LOOPID_MAP_SIZE || + qla2x00_is_reserved_id(vha, dev->loop_id)) { + dev->loop_id = FC_NO_LOOP_ID; + rval = QLA_FUNCTION_FAILED; + } else { + set_bit(dev->loop_id, ha->loop_id_map); + } + spin_unlock_irqrestore(&ha->vport_slock, flags); + + if (rval == QLA_SUCCESS) + ql_dbg(ql_dbg_disc, dev->vha, 0x2086, + "Assigning new loopid=%x, portid=%x.\n", + dev->loop_id, dev->d_id.b24); + else + ql_log(ql_log_warn, dev->vha, 0x2087, + "No loop_id's available, portid=%x.\n", + dev->d_id.b24); + + return rval; +} + +void qla2x00_clear_loop_id(fc_port_t *fcport) +{ + struct qla_hw_data *ha = fcport->vha->hw; + + if (fcport->loop_id == FC_NO_LOOP_ID || + qla2x00_is_reserved_id(fcport->vha, fcport->loop_id)) + return; + + clear_bit(fcport->loop_id, ha->loop_id_map); + fcport->loop_id = FC_NO_LOOP_ID; +} + static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, struct event_arg *ea) { @@ -1482,6 +1621,7 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id, u8 *port_name, u8 *node_name, void *pla, u8 fc4_type) { struct qla_work_evt *e; + e = qla2x00_alloc_work(vha, QLA_EVT_NEW_SESS); if (!e) return QLA_FUNCTION_FAILED; @@ -1558,6 +1698,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) return; { unsigned long flags; + fcport = qla2x00_find_fcport_by_nportid (vha, &ea->id, 1); if (fcport) { @@ -1620,21 +1761,21 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) */ void qla_rscn_replay(fc_port_t *fcport) { - struct event_arg ea; + struct event_arg ea; - switch (fcport->disc_state) { - case DSC_DELETE_PEND: - return; - default: - break; - } + switch (fcport->disc_state) { + case DSC_DELETE_PEND: + return; + default: + break; + } - if (fcport->scan_needed) { - memset(&ea, 0, sizeof(ea)); - ea.event = FCME_RSCN; - ea.id = fcport->d_id; - ea.id.b.rsvd_1 = RSCN_PORT_ADDR; - qla2x00_fcport_event_handler(fcport->vha, &ea); + if (fcport->scan_needed) { + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_RSCN; + ea.id = fcport->d_id; + ea.id.b.rsvd_1 = RSCN_PORT_ADDR; + qla2x00_fcport_event_handler(fcport->vha, &ea); } } @@ -1717,82 +1858,6 @@ done: return rval; } -static void -qla24xx_abort_iocb_timeout(void *data) -{ - srb_t *sp = data; - struct srb_iocb *abt = &sp->u.iocb_cmd; - - abt->u.abt.comp_status = CS_TIMEOUT; - sp->done(sp, QLA_FUNCTION_TIMEOUT); -} - -static void -qla24xx_abort_sp_done(void *ptr, int res) -{ - srb_t *sp = ptr; - struct srb_iocb *abt = &sp->u.iocb_cmd; - - if (del_timer(&sp->u.iocb_cmd.timer)) { - if (sp->flags & SRB_WAKEUP_ON_COMP) - complete(&abt->u.abt.comp); - else - sp->free(sp); - } -} - -int -qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) -{ - scsi_qla_host_t *vha = cmd_sp->vha; - struct srb_iocb *abt_iocb; - srb_t *sp; - int rval = QLA_FUNCTION_FAILED; - - sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, - GFP_ATOMIC); - if (!sp) - goto done; - - abt_iocb = &sp->u.iocb_cmd; - sp->type = SRB_ABT_CMD; - sp->name = "abort"; - sp->qpair = cmd_sp->qpair; - if (wait) - sp->flags = SRB_WAKEUP_ON_COMP; - - abt_iocb->timeout = qla24xx_abort_iocb_timeout; - init_completion(&abt_iocb->u.abt.comp); - /* FW can send 2 x ABTS's timeout/20s */ - qla2x00_init_timer(sp, 42); - - abt_iocb->u.abt.cmd_hndl = cmd_sp->handle; - abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id); - - sp->done = qla24xx_abort_sp_done; - - ql_dbg(ql_dbg_async, vha, 0x507c, - "Abort command issued - hdl=%x, type=%x\n", - cmd_sp->handle, cmd_sp->type); - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - if (wait) { - wait_for_completion(&abt_iocb->u.abt.comp); - rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? - QLA_SUCCESS : QLA_FUNCTION_FAILED; - } else { - goto done; - } - -done_free_sp: - sp->free(sp); -done: - return rval; -} - int qla24xx_async_abort_command(srb_t *sp) { @@ -2102,6 +2167,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) int rval; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; memset(&vha->qla_stats, 0, sizeof(vha->qla_stats)); memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat)); @@ -2136,6 +2202,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) ha->isp_ops->reset_chip(vha); + /* Check for secure flash support */ + if (IS_QLA28XX(ha)) { + if (RD_REG_DWORD(®->mailbox12) & BIT_0) { + ql_log(ql_log_info, vha, 0xffff, "Adapter is Secure\n"); + ha->flags.secure_adapter = 1; + } + } + + rval = qla2xxx_get_flash_info(vha); if (rval) { ql_log(ql_log_fatal, vha, 0x004f, @@ -2452,7 +2527,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha) * * Returns 0 on success. */ -void +int qla2x00_reset_chip(scsi_qla_host_t *vha) { unsigned long flags = 0; @@ -2460,9 +2535,10 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint32_t cnt; uint16_t cmd; + int rval = QLA_FUNCTION_FAILED; if (unlikely(pci_channel_offline(ha->pdev))) - return; + return rval; ha->isp_ops->disable_intrs(ha); @@ -2588,6 +2664,8 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) } spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_SUCCESS; } /** @@ -2828,14 +2906,15 @@ acquired: * * Returns 0 on success. */ -void +int qla24xx_reset_chip(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; + int rval = QLA_FUNCTION_FAILED; if (pci_channel_offline(ha->pdev) && ha->flags.pci_channel_io_perm_failure) { - return; + return rval; } ha->isp_ops->disable_intrs(ha); @@ -2843,7 +2922,9 @@ qla24xx_reset_chip(scsi_qla_host_t *vha) qla25xx_manipulate_risc_semaphore(vha); /* Perform RISC reset. */ - qla24xx_reset_risc(vha); + rval = qla24xx_reset_risc(vha); + + return rval; } /** @@ -3018,7 +3099,7 @@ qla2x00_alloc_offload_mem(scsi_qla_host_t *vha) if (IS_FWI2_CAPABLE(ha)) { /* Allocate memory for Fibre Channel Event Buffer. */ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) goto try_eft; if (ha->fce) @@ -3089,12 +3170,15 @@ eft_err: void qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) { + int rval; uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, eft_size, fce_size, mq_size; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0]; struct qla2xxx_fw_dump *fw_dump; + dma_addr_t tc_dma; + void *tc; dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0; req_q_size = rsp_q_size = 0; @@ -3106,7 +3190,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem); else if (IS_QLA81XX(ha)) fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); @@ -3118,40 +3202,72 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); if (ha->mqenable) { - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && + !IS_QLA28XX(ha)) mq_size = sizeof(struct qla2xxx_mq_chain); /* - * Allocate maximum buffer size for all queues. + * Allocate maximum buffer size for all queues - Q0. * Resizing must be done at end-of-dump processing. */ - mq_size += ha->max_req_queues * + mq_size += (ha->max_req_queues - 1) * (req->length * sizeof(request_t)); - mq_size += ha->max_rsp_queues * + mq_size += (ha->max_rsp_queues - 1) * (rsp->length * sizeof(response_t)); } if (ha->tgt.atio_ring) mq_size += ha->tgt.atio_q_length * sizeof(request_t); /* Allocate memory for Fibre Channel Event Buffer. */ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) goto try_eft; fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; try_eft: + if (ha->eft) + dma_free_coherent(&ha->pdev->dev, + EFT_SIZE, ha->eft, ha->eft_dma); + + /* Allocate memory for Extended Trace Buffer. */ + tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, + GFP_KERNEL); + if (!tc) { + ql_log(ql_log_warn, vha, 0x00c1, + "Unable to allocate (%d KB) for EFT.\n", + EFT_SIZE / 1024); + goto allocate; + } + + rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS); + if (rval) { + ql_log(ql_log_warn, vha, 0x00c2, + "Unable to initialize EFT (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, + tc_dma); + } ql_dbg(ql_dbg_init, vha, 0x00c3, "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024); eft_size = EFT_SIZE; } - if (IS_QLA27XX(ha)) { - if (!ha->fw_dump_template) { - ql_log(ql_log_warn, vha, 0x00ba, - "Failed missing fwdump template\n"); - return; + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + struct fwdt *fwdt = ha->fwdt; + uint j; + + for (j = 0; j < 2; j++, fwdt++) { + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0x00ba, + "-> fwdt%u no template\n", j); + continue; + } + ql_dbg(ql_dbg_init, vha, 0x00fa, + "-> fwdt%u calculating fwdump size...\n", j); + fwdt->dump_size = qla27xx_fwdt_calculate_dump_size( + vha, fwdt->template); + ql_dbg(ql_dbg_init, vha, 0x00fa, + "-> fwdt%u calculated fwdump size = %#lx bytes\n", + j, fwdt->dump_size); + dump_size += fwdt->dump_size; } - dump_size = qla27xx_fwdt_calculate_dump_size(vha); - ql_dbg(ql_dbg_init, vha, 0x00fa, - "-> allocating fwdump (%x bytes)...\n", dump_size); goto allocate; } @@ -3170,42 +3286,66 @@ try_eft: ha->exlogin_size; allocate: - if (!ha->fw_dump_len || dump_size != ha->fw_dump_len) { + if (!ha->fw_dump_len || dump_size > ha->fw_dump_alloc_len) { + + ql_dbg(ql_dbg_init, vha, 0x00c5, + "%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n", + __func__, dump_size, ha->fw_dump_len, + ha->fw_dump_alloc_len); + fw_dump = vmalloc(dump_size); if (!fw_dump) { ql_log(ql_log_warn, vha, 0x00c4, "Unable to allocate (%d KB) for firmware dump.\n", dump_size / 1024); } else { - if (ha->fw_dump) + mutex_lock(&ha->optrom_mutex); + if (ha->fw_dumped) { + memcpy(fw_dump, ha->fw_dump, ha->fw_dump_len); vfree(ha->fw_dump); - ha->fw_dump = fw_dump; - - ha->fw_dump_len = dump_size; - ql_dbg(ql_dbg_init, vha, 0x00c5, - "Allocated (%d KB) for firmware dump.\n", - dump_size / 1024); - - if (IS_QLA27XX(ha)) - return; - - ha->fw_dump->signature[0] = 'Q'; - ha->fw_dump->signature[1] = 'L'; - ha->fw_dump->signature[2] = 'G'; - ha->fw_dump->signature[3] = 'C'; - ha->fw_dump->version = htonl(1); - - ha->fw_dump->fixed_size = htonl(fixed_size); - ha->fw_dump->mem_size = htonl(mem_size); - ha->fw_dump->req_q_size = htonl(req_q_size); - ha->fw_dump->rsp_q_size = htonl(rsp_q_size); - - ha->fw_dump->eft_size = htonl(eft_size); - ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma)); - ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma)); + ha->fw_dump = fw_dump; + ha->fw_dump_alloc_len = dump_size; + ql_dbg(ql_dbg_init, vha, 0x00c5, + "Re-Allocated (%d KB) and save firmware dump.\n", + dump_size / 1024); + } else { + if (ha->fw_dump) + vfree(ha->fw_dump); + ha->fw_dump = fw_dump; + + ha->fw_dump_len = ha->fw_dump_alloc_len = + dump_size; + ql_dbg(ql_dbg_init, vha, 0x00c5, + "Allocated (%d KB) for firmware dump.\n", + dump_size / 1024); + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + mutex_unlock(&ha->optrom_mutex); + return; + } - ha->fw_dump->header_size = - htonl(offsetof(struct qla2xxx_fw_dump, isp)); + ha->fw_dump->signature[0] = 'Q'; + ha->fw_dump->signature[1] = 'L'; + ha->fw_dump->signature[2] = 'G'; + ha->fw_dump->signature[3] = 'C'; + ha->fw_dump->version = htonl(1); + + ha->fw_dump->fixed_size = htonl(fixed_size); + ha->fw_dump->mem_size = htonl(mem_size); + ha->fw_dump->req_q_size = htonl(req_q_size); + ha->fw_dump->rsp_q_size = htonl(rsp_q_size); + + ha->fw_dump->eft_size = htonl(eft_size); + ha->fw_dump->eft_addr_l = + htonl(LSD(ha->eft_dma)); + ha->fw_dump->eft_addr_h = + htonl(MSD(ha->eft_dma)); + + ha->fw_dump->header_size = + htonl(offsetof + (struct qla2xxx_fw_dump, isp)); + } + mutex_unlock(&ha->optrom_mutex); } } } @@ -3498,7 +3638,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) if (rval == QLA_SUCCESS) { qla24xx_detect_sfp(vha); - if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && + if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) && (ha->zio_mode == QLA_ZIO_MODE_6)) qla27xx_set_zio_threshold(vha, ha->last_zio_threshold); @@ -3570,7 +3711,7 @@ enable_82xx_npiv: spin_unlock_irqrestore(&ha->hardware_lock, flags); } - if (IS_QLA27XX(ha)) + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ha->flags.fac_supported = 1; else if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) { uint32_t size; @@ -3585,7 +3726,8 @@ enable_82xx_npiv: ha->fw_major_version, ha->fw_minor_version, ha->fw_subminor_version); - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ha->flags.fac_supported = 0; rval = QLA_SUCCESS; } @@ -3647,8 +3789,7 @@ qla2x00_update_fw_options(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0115, "Serial link options.\n"); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0109, - (uint8_t *)&ha->fw_seriallink_options, - sizeof(ha->fw_seriallink_options)); + ha->fw_seriallink_options, sizeof(ha->fw_seriallink_options)); ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; if (ha->fw_seriallink_options[3] & BIT_2) { @@ -3738,7 +3879,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) /* Move PUREX, ABTS RX & RIDA to ATIOQ */ if (ql2xmvasynctoatio && - (IS_QLA83XX(ha) || IS_QLA27XX(ha))) { + (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) { if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) ha->fw_options[2] |= BIT_11; @@ -3746,7 +3887,8 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha) ha->fw_options[2] &= ~BIT_11; } - if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { /* * Tell FW to track each exchange to prevent * driver from using stale exchange. @@ -3799,10 +3941,8 @@ qla2x00_config_rings(struct scsi_qla_host *vha) ha->init_cb->response_q_inpointer = cpu_to_le16(0); ha->init_cb->request_q_length = cpu_to_le16(req->length); ha->init_cb->response_q_length = cpu_to_le16(rsp->length); - ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); - ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); - ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); - ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); + put_unaligned_le64(req->dma, &ha->init_cb->request_q_address); + put_unaligned_le64(rsp->dma, &ha->init_cb->response_q_address); WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0); WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0); @@ -3829,21 +3969,19 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->response_q_inpointer = cpu_to_le16(0); icb->request_q_length = cpu_to_le16(req->length); icb->response_q_length = cpu_to_le16(rsp->length); - icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); - icb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); - icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); - icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); + put_unaligned_le64(req->dma, &icb->request_q_address); + put_unaligned_le64(rsp->dma, &icb->response_q_address); /* Setup ATIO queue dma pointers for target mode */ icb->atio_q_inpointer = cpu_to_le16(0); icb->atio_q_length = cpu_to_le16(ha->tgt.atio_q_length); - icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma)); - icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma)); + put_unaligned_le64(ha->tgt.atio_dma, &icb->atio_q_address); if (IS_SHADOW_REG_CAPABLE(ha)) icb->firmware_options_2 |= cpu_to_le32(BIT_30|BIT_29); - if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { icb->qos = cpu_to_le16(QLA_DEFAULT_QUE_QOS); icb->rid = cpu_to_le16(rid); if (ha->flags.msix_enabled) { @@ -4266,11 +4404,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, { char *st, *en; uint16_t index; + uint64_t zero[2] = { 0 }; struct qla_hw_data *ha = vha->hw; int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha); - if (memcmp(model, BINZERO, len) != 0) { + if (len > sizeof(zero)) + len = sizeof(zero); + if (memcmp(model, &zero, len) != 0) { strncpy(ha->model_number, model, len); st = en = ha->model_number; en += len - 1; @@ -4357,7 +4498,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) rval = QLA_SUCCESS; /* Determine NVRAM starting address. */ - ha->nvram_size = sizeof(nvram_t); + ha->nvram_size = sizeof(*nv); ha->nvram_base = 0; if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) if ((RD_REG_WORD(®->ctrl_status) >> 14) == 1) @@ -4371,16 +4512,15 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010f, "Contents of NVRAM.\n"); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0110, - (uint8_t *)nv, ha->nvram_size); + nv, ha->nvram_size); /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || - nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) { + if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) || + nv->nvram_version < 1) { /* Reset NVRAM data. */ ql_log(ql_log_warn, vha, 0x0064, - "Inconsistent NVRAM " - "detected: checksum=0x%x id=%c version=0x%x.\n", - chksum, nv->id[0], nv->nvram_version); + "Inconsistent NVRAM detected: checksum=%#x id=%.4s version=%#x.\n", + chksum, nv->id, nv->nvram_version); ql_log(ql_log_warn, vha, 0x0065, "Falling back to " "functioning (yet invalid -- WWPN) defaults.\n"); @@ -4629,7 +4769,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) ha->zio_mode = icb->add_firmware_options[0] & (BIT_3 | BIT_2 | BIT_1 | BIT_0); ha->zio_timer = icb->interrupt_delay_timer ? - icb->interrupt_delay_timer: 2; + icb->interrupt_delay_timer : 2; } icb->add_firmware_options[0] &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); @@ -4662,7 +4802,7 @@ qla2x00_rport_del(void *data) unsigned long flags; spin_lock_irqsave(fcport->vha->host->host_lock, flags); - rport = fcport->drport ? fcport->drport: fcport->rport; + rport = fcport->drport ? fcport->drport : fcport->rport; fcport->drport = NULL; spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); if (rport) { @@ -4675,6 +4815,23 @@ qla2x00_rport_del(void *data) } } +void qla2x00_set_fcport_state(fc_port_t *fcport, int state) +{ + int old_state; + + old_state = atomic_read(&fcport->state); + atomic_set(&fcport->state, state); + + /* Don't print state transitions during initial allocation of fcport */ + if (old_state && old_state != state) { + ql_dbg(ql_dbg_disc, fcport->vha, 0x207d, + "FCPort %8phC state transitioned from %s to %s - portid=%02x%02x%02x.\n", + fcport->port_name, port_state_str[old_state], + port_state_str[state], fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa); + } +} + /** * qla2x00_alloc_fcport() - Allocate a generic fcport. * @vha: HA context @@ -4741,6 +4898,8 @@ qla2x00_free_fcport(fc_port_t *fcport) fcport->ct_desc.ct_sns = NULL; } + list_del(&fcport->list); + qla2x00_clear_loop_id(fcport); kfree(fcport); } @@ -4762,6 +4921,7 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) int rval; unsigned long flags, save_flags; struct qla_hw_data *ha = vha->hw; + rval = QLA_SUCCESS; /* Get Initiator ID */ @@ -4943,8 +5103,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) ql_dbg(ql_dbg_disc, vha, 0x2011, "Entries in ID list (%d).\n", entries); ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075, - (uint8_t *)ha->gid_list, - entries * sizeof(struct gid_list_info)); + ha->gid_list, entries * sizeof(*ha->gid_list)); if (entries == 0) { spin_lock_irqsave(&vha->work_lock, flags); @@ -5194,16 +5353,23 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) rport->supported_classes = fcport->supported_classes; - rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; + rport_ids.roles = FC_PORT_ROLE_UNKNOWN; if (fcport->port_type == FCT_INITIATOR) - rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; + rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; if (fcport->port_type == FCT_TARGET) - rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; + rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET; + if (fcport->port_type & FCT_NVME_INITIATOR) + rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR; + if (fcport->port_type & FCT_NVME_TARGET) + rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET; + if (fcport->port_type & FCT_NVME_DISCOVERY) + rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY; ql_dbg(ql_dbg_disc, vha, 0x20ee, "%s %8phN. rport %p is %s mode\n", __func__, fcport->port_name, rport, - (fcport->port_type == FCT_TARGET) ? "tgt" : "ini"); + (fcport->port_type == FCT_TARGET) ? "tgt" : + ((fcport->port_type & FCT_NVME) ? "nvme" :"ini")); fc_remote_port_rolechg(rport, rport_ids.roles); } @@ -5237,7 +5403,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); fcport->deleted = 0; fcport->logout_on_delete = 1; - fcport->login_retry = vha->hw->login_retry_count; fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0; switch (vha->hw->current_topology) { @@ -5778,55 +5943,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) return (rval); } -/* - * qla2x00_find_new_loop_id - * Scan through our port list and find a new usable loop ID. - * - * Input: - * ha: adapter state pointer. - * dev: port structure pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - unsigned long flags = 0; - - rval = QLA_SUCCESS; - - spin_lock_irqsave(&ha->vport_slock, flags); - - dev->loop_id = find_first_zero_bit(ha->loop_id_map, - LOOPID_MAP_SIZE); - if (dev->loop_id >= LOOPID_MAP_SIZE || - qla2x00_is_reserved_id(vha, dev->loop_id)) { - dev->loop_id = FC_NO_LOOP_ID; - rval = QLA_FUNCTION_FAILED; - } else - set_bit(dev->loop_id, ha->loop_id_map); - - spin_unlock_irqrestore(&ha->vport_slock, flags); - - if (rval == QLA_SUCCESS) - ql_dbg(ql_dbg_disc, dev->vha, 0x2086, - "Assigning new loopid=%x, portid=%x.\n", - dev->loop_id, dev->d_id.b24); - else - ql_log(ql_log_warn, dev->vha, 0x2087, - "No loop_id's available, portid=%x.\n", - dev->d_id.b24); - - return (rval); -} - - /* FW does not set aside Loop id for MGMT Server/FFFFFAh */ int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *vha) @@ -6318,6 +6434,7 @@ qla83xx_initiating_reset(scsi_qla_host_t *vha) qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP); } else { const char *state = qla83xx_dev_state_to_string(dev_state); + ql_log(ql_log_info, vha, 0xb057, "HW State: %s.\n", state); /* SV: XXX: Is timeout required here? */ @@ -6639,6 +6756,14 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) if (vha->flags.online) { qla2x00_abort_isp_cleanup(vha); + if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) { + ha->flags.chip_reset_done = 1; + vha->flags.online = 1; + status = 0; + clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); + return status; + } + if (IS_QLA8031(ha)) { ql_dbg(ql_dbg_p3p, vha, 0xb05c, "Clearing fcoe driver presence.\n"); @@ -6879,7 +7004,7 @@ qla25xx_init_queues(struct qla_hw_data *ha) * Input: * ha = adapter block pointer. */ -void +int qla2x00_reset_adapter(scsi_qla_host_t *vha) { unsigned long flags = 0; @@ -6895,17 +7020,20 @@ qla2x00_reset_adapter(scsi_qla_host_t *vha) WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_SUCCESS; } -void +int qla24xx_reset_adapter(scsi_qla_host_t *vha) { unsigned long flags = 0; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + int rval = QLA_SUCCESS; if (IS_P3P_TYPE(ha)) - return; + return rval; vha->flags.online = 0; ha->isp_ops->disable_intrs(ha); @@ -6919,6 +7047,8 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha) if (IS_NOPOLLING_TYPE(ha)) ha->isp_ops->enable_intrs(ha); + + return rval; } /* On sparc systems, obtain port and node WWN from firmware @@ -6969,34 +7099,33 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) ha->vpd_base = FA_NVRAM_VPD1_ADDR; } - ha->nvram_size = sizeof(struct nvram_24xx); + ha->nvram_size = sizeof(*nv); ha->vpd_size = FA_NVRAM_VPD_SIZE; /* Get VPD data into cache */ ha->vpd = ha->nvram + VPD_OFFSET; - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, + ha->isp_ops->read_nvram(vha, ha->vpd, ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4); /* Get NVRAM data into cache and calculate checksum. */ dptr = (uint32_t *)nv; - ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base, - ha->nvram_size); + ha->isp_ops->read_nvram(vha, dptr, ha->nvram_base, ha->nvram_size); for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++) chksum += le32_to_cpu(*dptr); ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a, "Contents of NVRAM\n"); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010d, - (uint8_t *)nv, ha->nvram_size); + nv, ha->nvram_size); /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' - || nv->id[3] != ' ' || - nv->nvram_version < cpu_to_le16(ICB_VERSION)) { + if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) || + le16_to_cpu(nv->nvram_version) < ICB_VERSION) { /* Reset NVRAM data. */ ql_log(ql_log_warn, vha, 0x006b, - "Inconsistent NVRAM detected: checksum=0x%x id=%c " - "version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); + "Inconsistent NVRAM checksum=%#x id=%.4s version=%#x.\n", + chksum, nv->id, nv->nvram_version); + ql_dump_buffer(ql_dbg_init, vha, 0x006b, nv, sizeof(*nv)); ql_log(ql_log_warn, vha, 0x006c, "Falling back to functioning (yet invalid -- WWPN) " "defaults.\n"); @@ -7104,11 +7233,11 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) ha->flags.disable_risc_code_load = 0; ha->flags.enable_lip_reset = 0; ha->flags.enable_lip_full_login = - le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; + le32_to_cpu(nv->host_p) & BIT_10 ? 1 : 0; ha->flags.enable_target_reset = - le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; + le32_to_cpu(nv->host_p) & BIT_11 ? 1 : 0; ha->flags.enable_led_scheme = 0; - ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1 : 0; ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -7182,7 +7311,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & (BIT_3 | BIT_2 | BIT_1 | BIT_0); ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? - le16_to_cpu(icb->interrupt_delay_timer): 2; + le16_to_cpu(icb->interrupt_delay_timer) : 2; } icb->firmware_options_2 &= cpu_to_le32( ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); @@ -7205,128 +7334,311 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) return (rval); } -uint8_t qla27xx_find_valid_image(struct scsi_qla_host *vha) +static void +qla27xx_print_image(struct scsi_qla_host *vha, char *name, + struct qla27xx_image_status *image_status) +{ + ql_dbg(ql_dbg_init, vha, 0x018b, + "%s %s: mask=%#02x gen=%#04x ver=%u.%u map=%#01x sum=%#08x sig=%#08x\n", + name, "status", + image_status->image_status_mask, + le16_to_cpu(image_status->generation), + image_status->ver_major, + image_status->ver_minor, + image_status->bitmap, + le32_to_cpu(image_status->checksum), + le32_to_cpu(image_status->signature)); +} + +static bool +qla28xx_check_aux_image_status_signature( + struct qla27xx_image_status *image_status) +{ + ulong signature = le32_to_cpu(image_status->signature); + + return signature != QLA28XX_AUX_IMG_STATUS_SIGN; +} + +static bool +qla27xx_check_image_status_signature(struct qla27xx_image_status *image_status) +{ + ulong signature = le32_to_cpu(image_status->signature); + + return + signature != QLA27XX_IMG_STATUS_SIGN && + signature != QLA28XX_IMG_STATUS_SIGN; +} + +static ulong +qla27xx_image_status_checksum(struct qla27xx_image_status *image_status) +{ + uint32_t *p = (void *)image_status; + uint n = sizeof(*image_status) / sizeof(*p); + uint32_t sum = 0; + + for ( ; n--; p++) + sum += le32_to_cpup(p); + + return sum; +} + +static inline uint +qla28xx_component_bitmask(struct qla27xx_image_status *aux, uint bitmask) +{ + return aux->bitmap & bitmask ? + QLA27XX_SECONDARY_IMAGE : QLA27XX_PRIMARY_IMAGE; +} + +static void +qla28xx_component_status( + struct active_regions *active_regions, struct qla27xx_image_status *aux) +{ + active_regions->aux.board_config = + qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_BOARD_CONFIG); + + active_regions->aux.vpd_nvram = + qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_VPD_NVRAM); + + active_regions->aux.npiv_config_0_1 = + qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NPIV_CONFIG_0_1); + + active_regions->aux.npiv_config_2_3 = + qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NPIV_CONFIG_2_3); +} + +static int +qla27xx_compare_image_generation( + struct qla27xx_image_status *pri_image_status, + struct qla27xx_image_status *sec_image_status) +{ + /* calculate generation delta as uint16 (this accounts for wrap) */ + int16_t delta = + le16_to_cpu(pri_image_status->generation) - + le16_to_cpu(sec_image_status->generation); + + ql_dbg(ql_dbg_init, NULL, 0x0180, "generation delta = %d\n", delta); + + return delta; +} + +void +qla28xx_get_aux_images( + struct scsi_qla_host *vha, struct active_regions *active_regions) { - struct qla27xx_image_status pri_image_status, sec_image_status; - uint8_t valid_pri_image, valid_sec_image; - uint32_t *wptr; - uint32_t cnt, chksum, size; struct qla_hw_data *ha = vha->hw; + struct qla27xx_image_status pri_aux_image_status, sec_aux_image_status; + bool valid_pri_image = false, valid_sec_image = false; + bool active_pri_image = false, active_sec_image = false; - valid_pri_image = valid_sec_image = 1; - ha->active_image = 0; - size = sizeof(struct qla27xx_image_status) / sizeof(uint32_t); + if (!ha->flt_region_aux_img_status_pri) { + ql_dbg(ql_dbg_init, vha, 0x018a, "Primary aux image not addressed\n"); + goto check_sec_image; + } - if (!ha->flt_region_img_status_pri) { - valid_pri_image = 0; + qla24xx_read_flash_data(vha, (void *)&pri_aux_image_status, + ha->flt_region_aux_img_status_pri, + sizeof(pri_aux_image_status) >> 2); + qla27xx_print_image(vha, "Primary aux image", &pri_aux_image_status); + + if (qla28xx_check_aux_image_status_signature(&pri_aux_image_status)) { + ql_dbg(ql_dbg_init, vha, 0x018b, + "Primary aux image signature (%#x) not valid\n", + le32_to_cpu(pri_aux_image_status.signature)); + goto check_sec_image; + } + + if (qla27xx_image_status_checksum(&pri_aux_image_status)) { + ql_dbg(ql_dbg_init, vha, 0x018c, + "Primary aux image checksum failed\n"); goto check_sec_image; } - qla24xx_read_flash_data(vha, (uint32_t *)(&pri_image_status), - ha->flt_region_img_status_pri, size); + valid_pri_image = true; + + if (pri_aux_image_status.image_status_mask & 1) { + ql_dbg(ql_dbg_init, vha, 0x018d, + "Primary aux image is active\n"); + active_pri_image = true; + } + +check_sec_image: + if (!ha->flt_region_aux_img_status_sec) { + ql_dbg(ql_dbg_init, vha, 0x018a, + "Secondary aux image not addressed\n"); + goto check_valid_image; + } - if (pri_image_status.signature != QLA27XX_IMG_STATUS_SIGN) { + qla24xx_read_flash_data(vha, (void *)&sec_aux_image_status, + ha->flt_region_aux_img_status_sec, + sizeof(sec_aux_image_status) >> 2); + qla27xx_print_image(vha, "Secondary aux image", &sec_aux_image_status); + + if (qla28xx_check_aux_image_status_signature(&sec_aux_image_status)) { ql_dbg(ql_dbg_init, vha, 0x018b, - "Primary image signature (0x%x) not valid\n", - pri_image_status.signature); - valid_pri_image = 0; + "Secondary aux image signature (%#x) not valid\n", + le32_to_cpu(sec_aux_image_status.signature)); + goto check_valid_image; + } + + if (qla27xx_image_status_checksum(&sec_aux_image_status)) { + ql_dbg(ql_dbg_init, vha, 0x018c, + "Secondary aux image checksum failed\n"); + goto check_valid_image; + } + + valid_sec_image = true; + + if (sec_aux_image_status.image_status_mask & 1) { + ql_dbg(ql_dbg_init, vha, 0x018d, + "Secondary aux image is active\n"); + active_sec_image = true; + } + +check_valid_image: + if (valid_pri_image && active_pri_image && + valid_sec_image && active_sec_image) { + if (qla27xx_compare_image_generation(&pri_aux_image_status, + &sec_aux_image_status) >= 0) { + qla28xx_component_status(active_regions, + &pri_aux_image_status); + } else { + qla28xx_component_status(active_regions, + &sec_aux_image_status); + } + } else if (valid_pri_image && active_pri_image) { + qla28xx_component_status(active_regions, &pri_aux_image_status); + } else if (valid_sec_image && active_sec_image) { + qla28xx_component_status(active_regions, &sec_aux_image_status); + } + + ql_dbg(ql_dbg_init, vha, 0x018f, + "aux images active: BCFG=%u VPD/NVR=%u NPIV0/1=%u NPIV2/3=%u\n", + active_regions->aux.board_config, + active_regions->aux.vpd_nvram, + active_regions->aux.npiv_config_0_1, + active_regions->aux.npiv_config_2_3); +} + +void +qla27xx_get_active_image(struct scsi_qla_host *vha, + struct active_regions *active_regions) +{ + struct qla_hw_data *ha = vha->hw; + struct qla27xx_image_status pri_image_status, sec_image_status; + bool valid_pri_image = false, valid_sec_image = false; + bool active_pri_image = false, active_sec_image = false; + + if (!ha->flt_region_img_status_pri) { + ql_dbg(ql_dbg_init, vha, 0x018a, "Primary image not addressed\n"); goto check_sec_image; } - wptr = (uint32_t *)(&pri_image_status); - cnt = size; + qla24xx_read_flash_data(vha, (void *)(&pri_image_status), + ha->flt_region_img_status_pri, sizeof(pri_image_status) >> 2); + qla27xx_print_image(vha, "Primary image", &pri_image_status); - for (chksum = 0; cnt--; wptr++) - chksum += le32_to_cpu(*wptr); + if (qla27xx_check_image_status_signature(&pri_image_status)) { + ql_dbg(ql_dbg_init, vha, 0x018b, + "Primary image signature (%#x) not valid\n", + le32_to_cpu(pri_image_status.signature)); + goto check_sec_image; + } - if (chksum) { + if (qla27xx_image_status_checksum(&pri_image_status)) { ql_dbg(ql_dbg_init, vha, 0x018c, - "Checksum validation failed for primary image (0x%x)\n", - chksum); - valid_pri_image = 0; + "Primary image checksum failed\n"); + goto check_sec_image; + } + + valid_pri_image = true; + + if (pri_image_status.image_status_mask & 1) { + ql_dbg(ql_dbg_init, vha, 0x018d, + "Primary image is active\n"); + active_pri_image = true; } check_sec_image: if (!ha->flt_region_img_status_sec) { - valid_sec_image = 0; + ql_dbg(ql_dbg_init, vha, 0x018a, "Secondary image not addressed\n"); goto check_valid_image; } qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status), - ha->flt_region_img_status_sec, size); + ha->flt_region_img_status_sec, sizeof(sec_image_status) >> 2); + qla27xx_print_image(vha, "Secondary image", &sec_image_status); - if (sec_image_status.signature != QLA27XX_IMG_STATUS_SIGN) { - ql_dbg(ql_dbg_init, vha, 0x018d, - "Secondary image signature(0x%x) not valid\n", - sec_image_status.signature); - valid_sec_image = 0; + if (qla27xx_check_image_status_signature(&sec_image_status)) { + ql_dbg(ql_dbg_init, vha, 0x018b, + "Secondary image signature (%#x) not valid\n", + le32_to_cpu(sec_image_status.signature)); goto check_valid_image; } - wptr = (uint32_t *)(&sec_image_status); - cnt = size; - for (chksum = 0; cnt--; wptr++) - chksum += le32_to_cpu(*wptr); - if (chksum) { - ql_dbg(ql_dbg_init, vha, 0x018e, - "Checksum validation failed for secondary image (0x%x)\n", - chksum); - valid_sec_image = 0; + if (qla27xx_image_status_checksum(&sec_image_status)) { + ql_dbg(ql_dbg_init, vha, 0x018c, + "Secondary image checksum failed\n"); + goto check_valid_image; + } + + valid_sec_image = true; + + if (sec_image_status.image_status_mask & 1) { + ql_dbg(ql_dbg_init, vha, 0x018d, + "Secondary image is active\n"); + active_sec_image = true; } check_valid_image: - if (valid_pri_image && (pri_image_status.image_status_mask & 0x1)) - ha->active_image = QLA27XX_PRIMARY_IMAGE; - if (valid_sec_image && (sec_image_status.image_status_mask & 0x1)) { - if (!ha->active_image || - pri_image_status.generation_number < - sec_image_status.generation_number) - ha->active_image = QLA27XX_SECONDARY_IMAGE; + if (valid_pri_image && active_pri_image) + active_regions->global = QLA27XX_PRIMARY_IMAGE; + + if (valid_sec_image && active_sec_image) { + if (!active_regions->global || + qla27xx_compare_image_generation( + &pri_image_status, &sec_image_status) < 0) { + active_regions->global = QLA27XX_SECONDARY_IMAGE; + } } - ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x018f, "%s image\n", - ha->active_image == 0 ? "default bootld and fw" : - ha->active_image == 1 ? "primary" : - ha->active_image == 2 ? "secondary" : - "Invalid"); + ql_dbg(ql_dbg_init, vha, 0x018f, "active image %s (%u)\n", + active_regions->global == QLA27XX_DEFAULT_IMAGE ? + "default (boot/fw)" : + active_regions->global == QLA27XX_PRIMARY_IMAGE ? + "primary" : + active_regions->global == QLA27XX_SECONDARY_IMAGE ? + "secondary" : "invalid", + active_regions->global); +} - return ha->active_image; +bool qla24xx_risc_firmware_invalid(uint32_t *dword) +{ + return + !(dword[4] | dword[5] | dword[6] | dword[7]) || + !(~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]); } static int qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, uint32_t faddr) { - int rval = QLA_SUCCESS; - int segments, fragment; - uint32_t *dcode, dlen; - uint32_t risc_addr; - uint32_t risc_size; - uint32_t i; + int rval; + uint templates, segments, fragment; + ulong i; + uint j; + ulong dlen; + uint32_t *dcode; + uint32_t risc_addr, risc_size, risc_attr = 0; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + struct fwdt *fwdt = ha->fwdt; ql_dbg(ql_dbg_init, vha, 0x008b, "FW: Loading firmware from flash (%x).\n", faddr); - rval = QLA_SUCCESS; - - segments = FA_RISC_CODE_SEGMENTS; - dcode = (uint32_t *)req->ring; - *srisc_addr = 0; - - if (IS_QLA27XX(ha) && - qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE) - faddr = ha->flt_region_fw_sec; - - /* Validate firmware image by checking version. */ - qla24xx_read_flash_data(vha, dcode, faddr + 4, 4); - for (i = 0; i < 4; i++) - dcode[i] = be32_to_cpu(dcode[i]); - if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && - dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { + dcode = (void *)req->ring; + qla24xx_read_flash_data(vha, dcode, faddr, 8); + if (qla24xx_risc_firmware_invalid(dcode)) { ql_log(ql_log_fatal, vha, 0x008c, "Unable to verify the integrity of flash firmware " "image.\n"); @@ -7337,34 +7649,36 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, return QLA_FUNCTION_FAILED; } - while (segments && rval == QLA_SUCCESS) { - /* Read segment's load information. */ - qla24xx_read_flash_data(vha, dcode, faddr, 4); - + dcode = (void *)req->ring; + *srisc_addr = 0; + segments = FA_RISC_CODE_SEGMENTS; + for (j = 0; j < segments; j++) { + ql_dbg(ql_dbg_init, vha, 0x008d, + "-> Loading segment %u...\n", j); + qla24xx_read_flash_data(vha, dcode, faddr, 10); risc_addr = be32_to_cpu(dcode[2]); - *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; risc_size = be32_to_cpu(dcode[3]); + if (!*srisc_addr) { + *srisc_addr = risc_addr; + risc_attr = be32_to_cpu(dcode[9]); + } - fragment = 0; - while (risc_size > 0 && rval == QLA_SUCCESS) { - dlen = (uint32_t)(ha->fw_transfer_size >> 2); + dlen = ha->fw_transfer_size >> 2; + for (fragment = 0; risc_size; fragment++) { if (dlen > risc_size) dlen = risc_size; ql_dbg(ql_dbg_init, vha, 0x008e, - "Loading risc segment@ risc addr %x " - "number of dwords 0x%x offset 0x%x.\n", - risc_addr, dlen, faddr); - + "-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n", + fragment, risc_addr, faddr, dlen); qla24xx_read_flash_data(vha, dcode, faddr, dlen); for (i = 0; i < dlen; i++) dcode[i] = swab32(dcode[i]); - rval = qla2x00_load_ram(vha, req->dma, risc_addr, - dlen); + rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen); if (rval) { ql_log(ql_log_fatal, vha, 0x008f, - "Failed to load segment %d of firmware.\n", + "-> Failed load firmware fragment %u.\n", fragment); return QLA_FUNCTION_FAILED; } @@ -7372,107 +7686,82 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, faddr += dlen; risc_addr += dlen; risc_size -= dlen; - fragment++; } - - /* Next segment. */ - segments--; } - if (!IS_QLA27XX(ha)) - return rval; + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return QLA_SUCCESS; - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - - ql_dbg(ql_dbg_init, vha, 0x0161, - "Loading fwdump template from %x\n", faddr); - qla24xx_read_flash_data(vha, dcode, faddr, 7); - risc_size = be32_to_cpu(dcode[2]); - ql_dbg(ql_dbg_init, vha, 0x0162, - "-> array size %x dwords\n", risc_size); - if (risc_size == 0 || risc_size == ~0) - goto default_template; - - dlen = (risc_size - 8) * sizeof(*dcode); - ql_dbg(ql_dbg_init, vha, 0x0163, - "-> template allocating %x bytes...\n", dlen); - ha->fw_dump_template = vmalloc(dlen); - if (!ha->fw_dump_template) { - ql_log(ql_log_warn, vha, 0x0164, - "Failed fwdump template allocate %x bytes.\n", risc_size); - goto default_template; - } - - faddr += 7; - risc_size -= 8; - dcode = ha->fw_dump_template; - qla24xx_read_flash_data(vha, dcode, faddr, risc_size); - for (i = 0; i < risc_size; i++) - dcode[i] = le32_to_cpu(dcode[i]); - - if (!qla27xx_fwdt_template_valid(dcode)) { - ql_log(ql_log_warn, vha, 0x0165, - "Failed fwdump template validate\n"); - goto default_template; - } - - dlen = qla27xx_fwdt_template_size(dcode); - ql_dbg(ql_dbg_init, vha, 0x0166, - "-> template size %x bytes\n", dlen); - if (dlen > risc_size * sizeof(*dcode)) { - ql_log(ql_log_warn, vha, 0x0167, - "Failed fwdump template exceeds array by %zx bytes\n", - (size_t)(dlen - risc_size * sizeof(*dcode))); - goto default_template; - } - ha->fw_dump_template_len = dlen; - return rval; + templates = (risc_attr & BIT_9) ? 2 : 1; + ql_dbg(ql_dbg_init, vha, 0x0160, "-> templates = %u\n", templates); + for (j = 0; j < templates; j++, fwdt++) { + if (fwdt->template) + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + dcode = (void *)req->ring; + qla24xx_read_flash_data(vha, dcode, faddr, 7); + risc_size = be32_to_cpu(dcode[2]); + ql_dbg(ql_dbg_init, vha, 0x0161, + "-> fwdt%u template array at %#x (%#x dwords)\n", + j, faddr, risc_size); + if (!risc_size || !~risc_size) { + ql_dbg(ql_dbg_init, vha, 0x0162, + "-> fwdt%u failed to read array\n", j); + goto failed; + } -default_template: - ql_log(ql_log_warn, vha, 0x0168, "Using default fwdump template\n"); - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - - dlen = qla27xx_fwdt_template_default_size(); - ql_dbg(ql_dbg_init, vha, 0x0169, - "-> template allocating %x bytes...\n", dlen); - ha->fw_dump_template = vmalloc(dlen); - if (!ha->fw_dump_template) { - ql_log(ql_log_warn, vha, 0x016a, - "Failed fwdump template allocate %x bytes.\n", risc_size); - goto failed_template; - } - - dcode = ha->fw_dump_template; - risc_size = dlen / sizeof(*dcode); - memcpy(dcode, qla27xx_fwdt_template_default(), dlen); - for (i = 0; i < risc_size; i++) - dcode[i] = be32_to_cpu(dcode[i]); - - if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) { - ql_log(ql_log_warn, vha, 0x016b, - "Failed fwdump template validate\n"); - goto failed_template; - } - - dlen = qla27xx_fwdt_template_size(ha->fw_dump_template); - ql_dbg(ql_dbg_init, vha, 0x016c, - "-> template size %x bytes\n", dlen); - ha->fw_dump_template_len = dlen; - return rval; + /* skip header and ignore checksum */ + faddr += 7; + risc_size -= 8; + + ql_dbg(ql_dbg_init, vha, 0x0163, + "-> fwdt%u template allocate template %#x words...\n", + j, risc_size); + fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0x0164, + "-> fwdt%u failed allocate template.\n", j); + goto failed; + } -failed_template: - ql_log(ql_log_warn, vha, 0x016d, "Failed default fwdump template\n"); - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - return rval; + dcode = fwdt->template; + qla24xx_read_flash_data(vha, dcode, faddr, risc_size); + + if (!qla27xx_fwdt_template_valid(dcode)) { + ql_log(ql_log_warn, vha, 0x0165, + "-> fwdt%u failed template validate\n", j); + goto failed; + } + + dlen = qla27xx_fwdt_template_size(dcode); + ql_dbg(ql_dbg_init, vha, 0x0166, + "-> fwdt%u template size %#lx bytes (%#lx words)\n", + j, dlen, dlen / sizeof(*dcode)); + if (dlen > risc_size * sizeof(*dcode)) { + ql_log(ql_log_warn, vha, 0x0167, + "-> fwdt%u template exceeds array (%-lu bytes)\n", + j, dlen - risc_size * sizeof(*dcode)); + goto failed; + } + + fwdt->length = dlen; + ql_dbg(ql_dbg_init, vha, 0x0168, + "-> fwdt%u loaded template ok\n", j); + + faddr += risc_size + 1; + } + + return QLA_SUCCESS; + +failed: + if (fwdt->template) + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + return QLA_SUCCESS; } #define QLA_FW_URL "http://ldriver.qlogic.com/firmware/" @@ -7580,94 +7869,73 @@ static int qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; - int segments, fragment; - uint32_t *dcode, dlen; - uint32_t risc_addr; - uint32_t risc_size; - uint32_t i; + uint templates, segments, fragment; + uint32_t *dcode; + ulong dlen; + uint32_t risc_addr, risc_size, risc_attr = 0; + ulong i; + uint j; struct fw_blob *blob; - const uint32_t *fwcode; - uint32_t fwclen; + uint32_t *fwcode; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + struct fwdt *fwdt = ha->fwdt; + + ql_dbg(ql_dbg_init, vha, 0x0090, + "-> FW: Loading via request-firmware.\n"); - /* Load firmware blob. */ blob = qla2x00_request_firmware(vha); if (!blob) { - ql_log(ql_log_warn, vha, 0x0090, - "Firmware image unavailable.\n"); - ql_log(ql_log_warn, vha, 0x0091, - "Firmware images can be retrieved from: " - QLA_FW_URL ".\n"); + ql_log(ql_log_warn, vha, 0x0092, + "-> Firmware file not found.\n"); return QLA_FUNCTION_FAILED; } - ql_dbg(ql_dbg_init, vha, 0x0092, - "FW: Loading via request-firmware.\n"); - - rval = QLA_SUCCESS; - - segments = FA_RISC_CODE_SEGMENTS; - dcode = (uint32_t *)req->ring; - *srisc_addr = 0; - fwcode = (uint32_t *)blob->fw->data; - fwclen = 0; - - /* Validate firmware image by checking version. */ - if (blob->fw->size < 8 * sizeof(uint32_t)) { + fwcode = (void *)blob->fw->data; + dcode = fwcode; + if (qla24xx_risc_firmware_invalid(dcode)) { ql_log(ql_log_fatal, vha, 0x0093, "Unable to verify integrity of firmware image (%zd).\n", blob->fw->size); - return QLA_FUNCTION_FAILED; - } - for (i = 0; i < 4; i++) - dcode[i] = be32_to_cpu(fwcode[i + 4]); - if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && - dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { - ql_log(ql_log_fatal, vha, 0x0094, - "Unable to verify integrity of firmware image (%zd).\n", - blob->fw->size); ql_log(ql_log_fatal, vha, 0x0095, "Firmware data: %08x %08x %08x %08x.\n", dcode[0], dcode[1], dcode[2], dcode[3]); return QLA_FUNCTION_FAILED; } - while (segments && rval == QLA_SUCCESS) { + dcode = (void *)req->ring; + *srisc_addr = 0; + segments = FA_RISC_CODE_SEGMENTS; + for (j = 0; j < segments; j++) { + ql_dbg(ql_dbg_init, vha, 0x0096, + "-> Loading segment %u...\n", j); risc_addr = be32_to_cpu(fwcode[2]); - *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; risc_size = be32_to_cpu(fwcode[3]); - /* Validate firmware image size. */ - fwclen += risc_size * sizeof(uint32_t); - if (blob->fw->size < fwclen) { - ql_log(ql_log_fatal, vha, 0x0096, - "Unable to verify integrity of firmware image " - "(%zd).\n", blob->fw->size); - return QLA_FUNCTION_FAILED; + if (!*srisc_addr) { + *srisc_addr = risc_addr; + risc_attr = be32_to_cpu(fwcode[9]); } - fragment = 0; - while (risc_size > 0 && rval == QLA_SUCCESS) { - dlen = (uint32_t)(ha->fw_transfer_size >> 2); + dlen = ha->fw_transfer_size >> 2; + for (fragment = 0; risc_size; fragment++) { if (dlen > risc_size) dlen = risc_size; ql_dbg(ql_dbg_init, vha, 0x0097, - "Loading risc segment@ risc addr %x " - "number of dwords 0x%x.\n", risc_addr, dlen); + "-> Loading fragment %u: %#x <- %#x (%#lx words)...\n", + fragment, risc_addr, + (uint32_t)(fwcode - (typeof(fwcode))blob->fw->data), + dlen); for (i = 0; i < dlen; i++) dcode[i] = swab32(fwcode[i]); - rval = qla2x00_load_ram(vha, req->dma, risc_addr, - dlen); + rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen); if (rval) { ql_log(ql_log_fatal, vha, 0x0098, - "Failed to load segment %d of firmware.\n", + "-> Failed load firmware fragment %u.\n", fragment); return QLA_FUNCTION_FAILED; } @@ -7675,106 +7943,82 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) fwcode += dlen; risc_addr += dlen; risc_size -= dlen; - fragment++; } - - /* Next segment. */ - segments--; } - if (!IS_QLA27XX(ha)) - return rval; + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return QLA_SUCCESS; - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - - ql_dbg(ql_dbg_init, vha, 0x171, - "Loading fwdump template from %x\n", - (uint32_t)((void *)fwcode - (void *)blob->fw->data)); - risc_size = be32_to_cpu(fwcode[2]); - ql_dbg(ql_dbg_init, vha, 0x172, - "-> array size %x dwords\n", risc_size); - if (risc_size == 0 || risc_size == ~0) - goto default_template; - - dlen = (risc_size - 8) * sizeof(*fwcode); - ql_dbg(ql_dbg_init, vha, 0x0173, - "-> template allocating %x bytes...\n", dlen); - ha->fw_dump_template = vmalloc(dlen); - if (!ha->fw_dump_template) { - ql_log(ql_log_warn, vha, 0x0174, - "Failed fwdump template allocate %x bytes.\n", risc_size); - goto default_template; - } - - fwcode += 7; - risc_size -= 8; - dcode = ha->fw_dump_template; - for (i = 0; i < risc_size; i++) - dcode[i] = le32_to_cpu(fwcode[i]); - - if (!qla27xx_fwdt_template_valid(dcode)) { - ql_log(ql_log_warn, vha, 0x0175, - "Failed fwdump template validate\n"); - goto default_template; - } - - dlen = qla27xx_fwdt_template_size(dcode); - ql_dbg(ql_dbg_init, vha, 0x0176, - "-> template size %x bytes\n", dlen); - if (dlen > risc_size * sizeof(*fwcode)) { - ql_log(ql_log_warn, vha, 0x0177, - "Failed fwdump template exceeds array by %zx bytes\n", - (size_t)(dlen - risc_size * sizeof(*fwcode))); - goto default_template; - } - ha->fw_dump_template_len = dlen; - return rval; + templates = (risc_attr & BIT_9) ? 2 : 1; + ql_dbg(ql_dbg_init, vha, 0x0170, "-> templates = %u\n", templates); + for (j = 0; j < templates; j++, fwdt++) { + if (fwdt->template) + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + risc_size = be32_to_cpu(fwcode[2]); + ql_dbg(ql_dbg_init, vha, 0x0171, + "-> fwdt%u template array at %#x (%#x dwords)\n", + j, (uint32_t)((void *)fwcode - (void *)blob->fw->data), + risc_size); + if (!risc_size || !~risc_size) { + ql_dbg(ql_dbg_init, vha, 0x0172, + "-> fwdt%u failed to read array\n", j); + goto failed; + } -default_template: - ql_log(ql_log_warn, vha, 0x0178, "Using default fwdump template\n"); - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - - dlen = qla27xx_fwdt_template_default_size(); - ql_dbg(ql_dbg_init, vha, 0x0179, - "-> template allocating %x bytes...\n", dlen); - ha->fw_dump_template = vmalloc(dlen); - if (!ha->fw_dump_template) { - ql_log(ql_log_warn, vha, 0x017a, - "Failed fwdump template allocate %x bytes.\n", risc_size); - goto failed_template; - } - - dcode = ha->fw_dump_template; - risc_size = dlen / sizeof(*fwcode); - fwcode = qla27xx_fwdt_template_default(); - for (i = 0; i < risc_size; i++) - dcode[i] = be32_to_cpu(fwcode[i]); - - if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) { - ql_log(ql_log_warn, vha, 0x017b, - "Failed fwdump template validate\n"); - goto failed_template; - } - - dlen = qla27xx_fwdt_template_size(ha->fw_dump_template); - ql_dbg(ql_dbg_init, vha, 0x017c, - "-> template size %x bytes\n", dlen); - ha->fw_dump_template_len = dlen; - return rval; + /* skip header and ignore checksum */ + fwcode += 7; + risc_size -= 8; + + ql_dbg(ql_dbg_init, vha, 0x0173, + "-> fwdt%u template allocate template %#x words...\n", + j, risc_size); + fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0x0174, + "-> fwdt%u failed allocate template.\n", j); + goto failed; + } -failed_template: - ql_log(ql_log_warn, vha, 0x017d, "Failed default fwdump template\n"); - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; - return rval; + dcode = fwdt->template; + for (i = 0; i < risc_size; i++) + dcode[i] = fwcode[i]; + + if (!qla27xx_fwdt_template_valid(dcode)) { + ql_log(ql_log_warn, vha, 0x0175, + "-> fwdt%u failed template validate\n", j); + goto failed; + } + + dlen = qla27xx_fwdt_template_size(dcode); + ql_dbg(ql_dbg_init, vha, 0x0176, + "-> fwdt%u template size %#lx bytes (%#lx words)\n", + j, dlen, dlen / sizeof(*dcode)); + if (dlen > risc_size * sizeof(*dcode)) { + ql_log(ql_log_warn, vha, 0x0177, + "-> fwdt%u template exceeds array (%-lu bytes)\n", + j, dlen - risc_size * sizeof(*dcode)); + goto failed; + } + + fwdt->length = dlen; + ql_dbg(ql_dbg_init, vha, 0x0178, + "-> fwdt%u loaded template ok\n", j); + + fwcode += risc_size + 1; + } + + return QLA_SUCCESS; + +failed: + if (fwdt->template) + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + return QLA_SUCCESS; } int @@ -7803,32 +8047,50 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; struct qla_hw_data *ha = vha->hw; + struct active_regions active_regions = { }; if (ql2xfwloadbin == 2) goto try_blob_fw; - /* - * FW Load priority: + /* FW Load priority: * 1) Firmware residing in flash. * 2) Firmware via request-firmware interface (.bin file). - * 3) Golden-Firmware residing in flash -- limited operation. + * 3) Golden-Firmware residing in flash -- (limited operation). */ + + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + goto try_primary_fw; + + qla27xx_get_active_image(vha, &active_regions); + + if (active_regions.global != QLA27XX_SECONDARY_IMAGE) + goto try_primary_fw; + + ql_dbg(ql_dbg_init, vha, 0x008b, + "Loading secondary firmware image.\n"); + rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw_sec); + if (!rval) + return rval; + +try_primary_fw: + ql_dbg(ql_dbg_init, vha, 0x008b, + "Loading primary firmware image.\n"); rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw); - if (rval == QLA_SUCCESS) + if (!rval) return rval; try_blob_fw: rval = qla24xx_load_risc_blob(vha, srisc_addr); - if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw) + if (!rval || !ha->flt_region_gold_fw) return rval; ql_log(ql_log_info, vha, 0x0099, "Attempting to fallback to golden firmware.\n"); rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw); - if (rval != QLA_SUCCESS) + if (rval) return rval; - ql_log(ql_log_info, vha, 0x009a, "Update operational firmware.\n"); + ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n"); ha->flags.running_gold_fw = 1; return rval; } @@ -7963,6 +8225,7 @@ void qla84xx_put_chip(struct scsi_qla_host *vha) { struct qla_hw_data *ha = vha->hw; + if (ha->cs84xx) kref_put(&ha->cs84xx->kref, __qla84xx_chip_release); } @@ -7980,7 +8243,7 @@ qla84xx_init_chip(scsi_qla_host_t *vha) mutex_unlock(&ha->cs84xx->fw_update_mutex); - return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: + return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED : QLA_SUCCESS; } @@ -7997,25 +8260,48 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) uint32_t chksum; uint16_t cnt; struct qla_hw_data *ha = vha->hw; + uint32_t faddr; + struct active_regions active_regions = { }; rval = QLA_SUCCESS; icb = (struct init_cb_81xx *)ha->init_cb; nv = ha->nvram; /* Determine NVRAM starting address. */ - ha->nvram_size = sizeof(struct nvram_81xx); + ha->nvram_size = sizeof(*nv); ha->vpd_size = FA_NVRAM_VPD_SIZE; if (IS_P3P_TYPE(ha) || IS_QLA8031(ha)) ha->vpd_size = FA_VPD_SIZE_82XX; + if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) + qla28xx_get_aux_images(vha, &active_regions); + /* Get VPD data into cache */ ha->vpd = ha->nvram + VPD_OFFSET; - ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2, - ha->vpd_size); + + faddr = ha->flt_region_vpd; + if (IS_QLA28XX(ha)) { + if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE) + faddr = ha->flt_region_vpd_sec; + ql_dbg(ql_dbg_init, vha, 0x0110, + "Loading %s nvram image.\n", + active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? + "primary" : "secondary"); + } + qla24xx_read_flash_data(vha, ha->vpd, faddr, ha->vpd_size >> 2); /* Get NVRAM data into cache and calculate checksum. */ - ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, - ha->nvram_size); + faddr = ha->flt_region_nvram; + if (IS_QLA28XX(ha)) { + if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE) + faddr = ha->flt_region_nvram_sec; + } + ql_dbg(ql_dbg_init, vha, 0x0110, + "Loading %s nvram image.\n", + active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? + "primary" : "secondary"); + qla24xx_read_flash_data(vha, ha->nvram, faddr, ha->nvram_size >> 2); + dptr = (uint32_t *)nv; for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++) chksum += le32_to_cpu(*dptr); @@ -8023,17 +8309,16 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111, "Contents of NVRAM:\n"); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112, - (uint8_t *)nv, ha->nvram_size); + nv, ha->nvram_size); /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' - || nv->id[3] != ' ' || - nv->nvram_version < cpu_to_le16(ICB_VERSION)) { + if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) || + le16_to_cpu(nv->nvram_version) < ICB_VERSION) { /* Reset NVRAM data. */ ql_log(ql_log_info, vha, 0x0073, - "Inconsistent NVRAM detected: checksum=0x%x id=%c " - "version=0x%x.\n", chksum, nv->id[0], - le16_to_cpu(nv->nvram_version)); + "Inconsistent NVRAM checksum=%#x id=%.4s version=%#x.\n", + chksum, nv->id, le16_to_cpu(nv->nvram_version)); + ql_dump_buffer(ql_dbg_init, vha, 0x0073, nv, sizeof(*nv)); ql_log(ql_log_info, vha, 0x0074, "Falling back to functioning (yet invalid -- WWPN) " "defaults.\n"); @@ -8154,11 +8439,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) ha->flags.disable_risc_code_load = 0; ha->flags.enable_lip_reset = 0; ha->flags.enable_lip_full_login = - le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; + le32_to_cpu(nv->host_p) & BIT_10 ? 1 : 0; ha->flags.enable_target_reset = - le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; + le32_to_cpu(nv->host_p) & BIT_11 ? 1 : 0; ha->flags.enable_led_scheme = 0; - ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1 : 0; ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -8222,7 +8507,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) ha->login_retry_count = ql2xloginretrycount; /* if not running MSI-X we need handshaking on interrupts */ - if (!vha->hw->flags.msix_enabled && (IS_QLA83XX(ha) || IS_QLA27XX(ha))) + if (!vha->hw->flags.msix_enabled && + (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) icb->firmware_options_2 |= cpu_to_le32(BIT_22); /* Enable ZIO. */ @@ -8230,7 +8516,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & (BIT_3 | BIT_2 | BIT_1 | BIT_0); ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? - le16_to_cpu(icb->interrupt_delay_timer): 2; + le16_to_cpu(icb->interrupt_delay_timer) : 2; } icb->firmware_options_2 &= cpu_to_le32( ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); @@ -8255,12 +8541,6 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* N2N: driver will initiate Login instead of FW */ icb->firmware_options_3 |= BIT_8; - if (IS_QLA27XX(ha)) { - icb->firmware_options_3 |= BIT_8; - ql_dbg(ql_log_info, vha, 0x0075, - "Enabling direct connection.\n"); - } - if (rval) { ql_log(ql_log_warn, vha, 0x0076, "NVRAM configuration failed.\n"); @@ -8621,7 +8901,6 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, "Failed to allocate memory for queue pair.\n"); return NULL; } - memset(qpair, 0, sizeof(struct qla_qpair)); qpair->hw = vha->hw; qpair->vha = vha; @@ -8668,7 +8947,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->msix->in_use = 1; list_add_tail(&qpair->qp_list_elem, &vha->qp_list); qpair->pdev = ha->pdev; - if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) + if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) qpair->reqq_start_iocbs = qla_83xx_start_iocbs; mutex_unlock(&ha->mq_lock); diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 512c3c37b447..bf063c664352 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -91,43 +91,6 @@ host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize) } static inline void -qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha) -{ - int i; - - if (IS_FWI2_CAPABLE(ha)) - return; - - for (i = 0; i < SNS_FIRST_LOOP_ID; i++) - set_bit(i, ha->loop_id_map); - set_bit(MANAGEMENT_SERVER, ha->loop_id_map); - set_bit(BROADCAST, ha->loop_id_map); -} - -static inline int -qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id) -{ - struct qla_hw_data *ha = vha->hw; - if (IS_FWI2_CAPABLE(ha)) - return (loop_id > NPH_LAST_HANDLE); - - return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) || - loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST); -} - -static inline void -qla2x00_clear_loop_id(fc_port_t *fcport) { - struct qla_hw_data *ha = fcport->vha->hw; - - if (fcport->loop_id == FC_NO_LOOP_ID || - qla2x00_is_reserved_id(fcport->vha, fcport->loop_id)) - return; - - clear_bit(fcport->loop_id, ha->loop_id_map); - fcport->loop_id = FC_NO_LOOP_ID; -} - -static inline void qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx) { struct dsd_dma *dsd, *tdsd; @@ -142,25 +105,6 @@ qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx) INIT_LIST_HEAD(&ctx->dsd_list); } -static inline void -qla2x00_set_fcport_state(fc_port_t *fcport, int state) -{ - int old_state; - - old_state = atomic_read(&fcport->state); - atomic_set(&fcport->state, state); - - /* Don't print state transitions during initial allocation of fcport */ - if (old_state && old_state != state) { - ql_dbg(ql_dbg_disc, fcport->vha, 0x207d, - "FCPort %8phC state transitioned from %s to %s - " - "portid=%02x%02x%02x.\n", fcport->port_name, - port_state_str[old_state], port_state_str[state], - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - } -} - static inline int qla2x00_hba_err_chk_enabled(srb_t *sp) { @@ -240,6 +184,7 @@ done: static inline void qla2xxx_rel_qpair_sp(struct qla_qpair *qpair, srb_t *sp) { + sp->qpair = NULL; mempool_free(sp, qpair->srb_mempool); QLA_QPAIR_MARK_NOT_BUSY(qpair); } @@ -274,18 +219,6 @@ qla2x00_rel_sp(srb_t *sp) qla2xxx_rel_qpair_sp(sp->qpair, sp); } -static inline void -qla2x00_init_timer(srb_t *sp, unsigned long tmo) -{ - timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0); - sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ; - sp->free = qla2x00_sp_free; - init_completion(&sp->comp); - if (IS_QLAFX00(sp->vha->hw) && (sp->type == SRB_FXIOCB_DCMD)) - init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); - add_timer(&sp->u.iocb_cmd.timer); -} - static inline int qla2x00_gid_list_size(struct qla_hw_data *ha) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 456a41d2e2c6..9312b19ed708 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -107,7 +107,7 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) cont_pkt = (cont_entry_t *)req->ring_ptr; /* Load packet defaults. */ - *((uint32_t *)(&cont_pkt->entry_type)) = cpu_to_le32(CONTINUE_TYPE); + put_unaligned_le32(CONTINUE_TYPE, &cont_pkt->entry_type); return (cont_pkt); } @@ -136,9 +136,8 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) cont_pkt = (cont_a64_entry_t *)req->ring_ptr; /* Load packet defaults. */ - *((uint32_t *)(&cont_pkt->entry_type)) = IS_QLAFX00(vha->hw) ? - cpu_to_le32(CONTINUE_A64_TYPE_FX00) : - cpu_to_le32(CONTINUE_A64_TYPE); + put_unaligned_le32(IS_QLAFX00(vha->hw) ? CONTINUE_A64_TYPE_FX00 : + CONTINUE_A64_TYPE, &cont_pkt->entry_type); return (cont_pkt); } @@ -193,7 +192,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, uint16_t tot_dsds) { uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd32 *cur_dsd; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; struct scatterlist *sg; @@ -202,8 +201,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 2 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - cpu_to_le32(COMMAND_TYPE); + put_unaligned_le32(COMMAND_TYPE, &cmd_pkt->entry_type); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { @@ -215,8 +213,8 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); /* Three DSDs are available in the Command Type 2 IOCB */ - avail_dsds = 3; - cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; + avail_dsds = ARRAY_SIZE(cmd_pkt->dsd32); + cur_dsd = cmd_pkt->dsd32; /* Load data segments */ scsi_for_each_sg(cmd, sg, tot_dsds, i) { @@ -229,12 +227,11 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, * Type 0 IOCB. */ cont_pkt = qla2x00_prep_cont_type0_iocb(vha); - cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; - avail_dsds = 7; + cur_dsd = cont_pkt->dsd; + avail_dsds = ARRAY_SIZE(cont_pkt->dsd); } - *cur_dsd++ = cpu_to_le32(sg_dma_address(sg)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd32(&cur_dsd, sg); avail_dsds--; } } @@ -251,7 +248,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, uint16_t tot_dsds) { uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; struct scatterlist *sg; @@ -260,7 +257,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_A64_TYPE); + put_unaligned_le32(COMMAND_A64_TYPE, &cmd_pkt->entry_type); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { @@ -272,12 +269,11 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); /* Two DSDs are available in the Command Type 3 IOCB */ - avail_dsds = 2; - cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; + avail_dsds = ARRAY_SIZE(cmd_pkt->dsd64); + cur_dsd = cmd_pkt->dsd64; /* Load data segments */ scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; cont_a64_entry_t *cont_pkt; /* Allocate additional continuation packets? */ @@ -287,14 +283,11 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, * Type 1 IOCB. */ cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); - cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; - avail_dsds = 5; + cur_dsd = cont_pkt->dsd; + avail_dsds = ARRAY_SIZE(cont_pkt->dsd); } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } } @@ -467,7 +460,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) req->ring_ptr++; /* Set chip new ring index. */ - if (ha->mqenable || IS_QLA27XX(ha)) { + if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { WRT_REG_DWORD(req->req_q_in, req->ring_index); } else if (IS_QLA83XX(ha)) { WRT_REG_DWORD(req->req_q_in, req->ring_index); @@ -580,13 +573,11 @@ static inline int qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, uint16_t tot_dsds) { - uint32_t *cur_dsd = NULL; + struct dsd64 *cur_dsd = NULL, *next_dsd; scsi_qla_host_t *vha; struct qla_hw_data *ha; struct scsi_cmnd *cmd; struct scatterlist *cur_seg; - uint32_t *dsd_seg; - void *next_dsd; uint8_t avail_dsds; uint8_t first_iocb = 1; uint32_t dsd_list_len; @@ -596,7 +587,7 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_6); + put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { @@ -638,32 +629,27 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, if (first_iocb) { first_iocb = 0; - dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; - *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len); + put_unaligned_le64(dsd_ptr->dsd_list_dma, + &cmd_pkt->fcp_dsd.address); + cmd_pkt->fcp_dsd.length = cpu_to_le32(dsd_list_len); } else { - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(dsd_list_len); + put_unaligned_le64(dsd_ptr->dsd_list_dma, + &cur_dsd->address); + cur_dsd->length = cpu_to_le32(dsd_list_len); + cur_dsd++; } - cur_dsd = (uint32_t *)next_dsd; + cur_dsd = next_dsd; while (avail_dsds) { - dma_addr_t sle_dma; - - sle_dma = sg_dma_address(cur_seg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); + append_dsd64(&cur_dsd, cur_seg); cur_seg = sg_next(cur_seg); avail_dsds--; } } /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; + cur_dsd->address = 0; + cur_dsd->length = 0; + cur_dsd++; cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE; return 0; } @@ -702,7 +688,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, uint16_t tot_dsds, struct req_que *req) { uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; struct scatterlist *sg; @@ -711,7 +697,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_7); + put_unaligned_le32(COMMAND_TYPE_7, &cmd_pkt->entry_type); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { @@ -734,12 +720,11 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, /* One DSD is available in the Command Type 3 IOCB */ avail_dsds = 1; - cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; + cur_dsd = &cmd_pkt->dsd; /* Load data segments */ scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; cont_a64_entry_t *cont_pkt; /* Allocate additional continuation packets? */ @@ -749,14 +734,11 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Type 1 IOCB. */ cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req); - cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; - avail_dsds = 5; + cur_dsd = cont_pkt->dsd; + avail_dsds = ARRAY_SIZE(cont_pkt->dsd); } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } } @@ -892,14 +874,14 @@ qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx, int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, - uint32_t *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) + struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) { void *next_dsd; uint8_t avail_dsds = 0; uint32_t dsd_list_len; struct dsd_dma *dsd_ptr; struct scatterlist *sg_prot; - uint32_t *cur_dsd = dsd; + struct dsd64 *cur_dsd = dsd; uint16_t used_dsds = tot_dsds; uint32_t prot_int; /* protection interval */ uint32_t partial; @@ -973,14 +955,14 @@ alloc_and_fill: /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; + put_unaligned_le64(dsd_ptr->dsd_list_dma, + &cur_dsd->address); + cur_dsd->length = cpu_to_le32(dsd_list_len); + cur_dsd = next_dsd; } - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sle_dma_len); + put_unaligned_le64(sle_dma, &cur_dsd->address); + cur_dsd->length = cpu_to_le32(sle_dma_len); + cur_dsd++; avail_dsds--; if (partial == 0) { @@ -999,22 +981,22 @@ alloc_and_fill: } } /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; + cur_dsd->address = 0; + cur_dsd->length = 0; + cur_dsd++; return 0; } int -qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, - uint16_t tot_dsds, struct qla_tc_param *tc) +qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, + struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) { void *next_dsd; uint8_t avail_dsds = 0; uint32_t dsd_list_len; struct dsd_dma *dsd_ptr; struct scatterlist *sg, *sgl; - uint32_t *cur_dsd = dsd; + struct dsd64 *cur_dsd = dsd; int i; uint16_t used_dsds = tot_dsds; struct scsi_cmnd *cmd; @@ -1031,8 +1013,6 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, for_each_sg(sgl, sg, tot_dsds, i) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? @@ -1072,29 +1052,25 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, } /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; + put_unaligned_le64(dsd_ptr->dsd_list_dma, + &cur_dsd->address); + cur_dsd->length = cpu_to_le32(dsd_list_len); + cur_dsd = next_dsd; } - sle_dma = sg_dma_address(sg); - - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; + cur_dsd->address = 0; + cur_dsd->length = 0; + cur_dsd++; return 0; } int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, - uint32_t *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc) + struct dsd64 *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc) { struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd; struct scatterlist *sg, *sgl; @@ -1109,6 +1085,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, if (sp) { struct scsi_cmnd *cmd = GET_CMD_SP(sp); + sgl = scsi_prot_sglist(cmd); vha = sp->vha; difctx = sp->u.scmd.ctx; @@ -1314,16 +1291,15 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, } /* add new list to cmd iocb or last list */ - *cur_dsd++ = - cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = - cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; + put_unaligned_le64(dsd_ptr->dsd_list_dma, + &cur_dsd->address); + cur_dsd->length = cpu_to_le32(dsd_list_len); cur_dsd = dsd_ptr->dsd_addr; } - *cur_dsd++ = cpu_to_le32(LSD(dif_dsd->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dif_dsd->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(sglen); + put_unaligned_le64(dif_dsd->dsd_list_dma, + &cur_dsd->address); + cur_dsd->length = cpu_to_le32(sglen); + cur_dsd++; avail_dsds--; difctx->dif_bundl_len -= sglen; track_difbundl_buf--; @@ -1334,8 +1310,6 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, difctx->no_ldif_dsd, difctx->no_dif_bundl); } else { for_each_sg(sgl, sg, tot_dsds, i) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? @@ -1375,24 +1349,19 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, } /* add new list to cmd iocb or last list */ - *cur_dsd++ = - cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = - cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; + put_unaligned_le64(dsd_ptr->dsd_list_dma, + &cur_dsd->address); + cur_dsd->length = cpu_to_le32(dsd_list_len); cur_dsd = dsd_ptr->dsd_addr; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } } /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; + cur_dsd->address = 0; + cur_dsd->length = 0; + cur_dsd++; return 0; } /** @@ -1405,11 +1374,12 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, * @tot_prot_dsds: Total number of segments with protection information * @fw_prot_opts: Protection options to be passed to firmware */ -inline int +static inline int qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) { - uint32_t *cur_dsd, *fcp_dl; + struct dsd64 *cur_dsd; + uint32_t *fcp_dl; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; uint32_t total_bytes = 0; @@ -1427,7 +1397,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type CRC_2 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_CRC_2); + put_unaligned_le32(COMMAND_TYPE_CRC_2, &cmd_pkt->entry_type); vha = sp->vha; ha = vha->hw; @@ -1475,8 +1445,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *) &crc_ctx_pkt->ref_tag, tot_prot_dsds); - cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma)); - cmd_pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma)); + put_unaligned_le64(crc_ctx_dma, &cmd_pkt->crc_context_address); cmd_pkt->crc_context_len = CRC_CONTEXT_LEN_FW; /* Determine SCSI command length -- align to 4 byte boundary */ @@ -1503,10 +1472,8 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun); memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); - cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32( - LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); - cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32( - MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); + put_unaligned_le64(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF, + &cmd_pkt->fcp_cmnd_dseg_address); fcp_cmnd->task_management = 0; fcp_cmnd->task_attribute = TSK_SIMPLE; @@ -1520,18 +1487,18 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, switch (scsi_get_prot_op(GET_CMD_SP(sp))) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: - total_bytes = data_bytes; - data_bytes += dif_bytes; - break; + total_bytes = data_bytes; + data_bytes += dif_bytes; + break; case SCSI_PROT_READ_STRIP: case SCSI_PROT_WRITE_INSERT: case SCSI_PROT_READ_PASS: case SCSI_PROT_WRITE_PASS: - total_bytes = data_bytes + dif_bytes; - break; + total_bytes = data_bytes + dif_bytes; + break; default: - BUG(); + BUG(); } if (!qla2x00_hba_err_chk_enabled(sp)) @@ -1548,7 +1515,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, } if (!bundling) { - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address; + cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd; } else { /* * Configure Bundling if we need to fetch interlaving @@ -1558,7 +1525,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - tot_prot_dsds); - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address; + cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd; } /* Finish the common fields of CRC pkt */ @@ -1591,7 +1558,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, if (bundling && tot_prot_dsds) { /* Walks dif segments */ cmd_pkt->control_flags |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; + cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd; if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, tot_prot_dsds, NULL)) goto crc_queuing_error; @@ -2325,7 +2292,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) if (req->cnt < req_cnt + 2) { if (qpair->use_shadow_reg) cnt = *req->out_ptr; - else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) + else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) cnt = RD_REG_DWORD(®->isp25mq.req_q_out); else if (IS_P3P_TYPE(ha)) cnt = RD_REG_DWORD(®->isp82.req_q_out); @@ -2494,7 +2462,7 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); mbx->mb1 = HAS_EXTENDED_IDS(ha) ? - cpu_to_le16(sp->fcport->loop_id): + cpu_to_le16(sp->fcport->loop_id) : cpu_to_le16(sp->fcport->loop_id << 8); mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | @@ -2565,6 +2533,16 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) } } +void qla2x00_init_timer(srb_t *sp, unsigned long tmo) +{ + timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0); + sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ; + sp->free = qla2x00_sp_free; + if (IS_QLAFX00(sp->vha->hw) && sp->type == SRB_FXIOCB_DCMD) + init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); + add_timer(&sp->u.iocb_cmd.timer); +} + static void qla2x00_els_dcmd_sp_free(void *data) { @@ -2726,18 +2704,13 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { els_iocb->tx_byte_count = els_iocb->tx_len = sizeof(struct els_plogi_payload); - els_iocb->tx_address[0] = - cpu_to_le32(LSD(elsio->u.els_plogi.els_plogi_pyld_dma)); - els_iocb->tx_address[1] = - cpu_to_le32(MSD(elsio->u.els_plogi.els_plogi_pyld_dma)); - + put_unaligned_le64(elsio->u.els_plogi.els_plogi_pyld_dma, + &els_iocb->tx_address); els_iocb->rx_dsd_count = 1; els_iocb->rx_byte_count = els_iocb->rx_len = sizeof(struct els_plogi_payload); - els_iocb->rx_address[0] = - cpu_to_le32(LSD(elsio->u.els_plogi.els_resp_pyld_dma)); - els_iocb->rx_address[1] = - cpu_to_le32(MSD(elsio->u.els_plogi.els_resp_pyld_dma)); + put_unaligned_le64(elsio->u.els_plogi.els_resp_pyld_dma, + &els_iocb->rx_address); ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI ELS IOCB:\n"); @@ -2745,15 +2718,12 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) (uint8_t *)els_iocb, 0x70); } else { els_iocb->tx_byte_count = sizeof(struct els_logo_payload); - els_iocb->tx_address[0] = - cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma)); - els_iocb->tx_address[1] = - cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma)); + put_unaligned_le64(elsio->u.els_logo.els_logo_pyld_dma, + &els_iocb->tx_address); els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload)); els_iocb->rx_byte_count = 0; - els_iocb->rx_address[0] = 0; - els_iocb->rx_address[1] = 0; + els_iocb->rx_address = 0; els_iocb->rx_len = 0; } @@ -2976,17 +2946,13 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->tx_byte_count = cpu_to_le32(bsg_job->request_payload.payload_len); - els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->request_payload.sg_list))); + put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list), + &els_iocb->tx_address); els_iocb->tx_len = cpu_to_le32(sg_dma_len (bsg_job->request_payload.sg_list)); - els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); + put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list), + &els_iocb->rx_address); els_iocb->rx_len = cpu_to_le32(sg_dma_len (bsg_job->reply_payload.sg_list)); @@ -2997,14 +2963,13 @@ static void qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) { uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; struct scatterlist *sg; int index; uint16_t tot_dsds; scsi_qla_host_t *vha = sp->vha; struct qla_hw_data *ha = vha->hw; struct bsg_job *bsg_job = sp->u.bsg_job; - int loop_iterartion = 0; int entry_count = 1; memset(ct_iocb, 0, sizeof(ms_iocb_entry_t)); @@ -3024,25 +2989,20 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) ct_iocb->rsp_bytecount = cpu_to_le32(bsg_job->reply_payload.payload_len); - ct_iocb->dseg_req_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - ct_iocb->dseg_req_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - ct_iocb->dseg_req_length = ct_iocb->req_bytecount; + put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list), + &ct_iocb->req_dsd.address); + ct_iocb->req_dsd.length = ct_iocb->req_bytecount; - ct_iocb->dseg_rsp_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - ct_iocb->dseg_rsp_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - ct_iocb->dseg_rsp_length = ct_iocb->rsp_bytecount; + put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list), + &ct_iocb->rsp_dsd.address); + ct_iocb->rsp_dsd.length = ct_iocb->rsp_bytecount; avail_dsds = 1; - cur_dsd = (uint32_t *)ct_iocb->dseg_rsp_address; + cur_dsd = &ct_iocb->rsp_dsd; index = 0; tot_dsds = bsg_job->reply_payload.sg_cnt; for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { - dma_addr_t sle_dma; cont_a64_entry_t *cont_pkt; /* Allocate additional continuation packets? */ @@ -3053,16 +3013,12 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) */ cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->hw->req_q_map[0]); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + cur_dsd = cont_pkt->dsd; avail_dsds = 5; entry_count++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - loop_iterartion++; + append_dsd64(&cur_dsd, sg); avail_dsds--; } ct_iocb->entry_count = entry_count; @@ -3074,7 +3030,7 @@ static void qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) { uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; struct scatterlist *sg; int index; uint16_t cmd_dsds, rsp_dsds; @@ -3103,12 +3059,10 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) cpu_to_le32(bsg_job->request_payload.payload_len); avail_dsds = 2; - cur_dsd = (uint32_t *)ct_iocb->dseg_0_address; + cur_dsd = ct_iocb->dsd; index = 0; for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { /* @@ -3117,23 +3071,18 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) */ cont_pkt = qla2x00_prep_cont_type1_iocb( vha, ha->req_q_map[0]); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + cur_dsd = cont_pkt->dsd; avail_dsds = 5; entry_count++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } index = 0; for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { /* @@ -3142,15 +3091,12 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) */ cont_pkt = qla2x00_prep_cont_type1_iocb(vha, ha->req_q_map[0]); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + cur_dsd = cont_pkt->dsd; avail_dsds = 5; entry_count++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } ct_iocb->entry_count = entry_count; @@ -3371,10 +3317,8 @@ sufficient_dsds: *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); - cmd_pkt->fcp_cmnd_dseg_address[0] = - cpu_to_le32(LSD(ctx->fcp_cmnd_dma)); - cmd_pkt->fcp_cmnd_dseg_address[1] = - cpu_to_le32(MSD(ctx->fcp_cmnd_dma)); + put_unaligned_le64(ctx->fcp_cmnd_dma, + &cmd_pkt->fcp_cmnd_dseg_address); sp->flags |= SRB_FCP_CMND_DMA_VALID; cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); @@ -3386,6 +3330,7 @@ sufficient_dsds: cmd_pkt->entry_status = (uint8_t) rsp->id; } else { struct cmd_type_7 *cmd_pkt; + req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); if (req->cnt < (req_cnt + 2)) { cnt = (uint16_t)RD_REG_DWORD_RELAXED( @@ -3590,15 +3535,13 @@ qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt) cmd_pkt->tx_dseg_count = 1; cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len; - cmd_pkt->dseg0_len = nvme->u.nvme.cmd_len; - cmd_pkt->dseg0_address[0] = cpu_to_le32(LSD(nvme->u.nvme.cmd_dma)); - cmd_pkt->dseg0_address[1] = cpu_to_le32(MSD(nvme->u.nvme.cmd_dma)); + cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len; + put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address); cmd_pkt->rx_dseg_count = 1; cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len; - cmd_pkt->dseg1_len = nvme->u.nvme.rsp_len; - cmd_pkt->dseg1_address[0] = cpu_to_le32(LSD(nvme->u.nvme.rsp_dma)); - cmd_pkt->dseg1_address[1] = cpu_to_le32(MSD(nvme->u.nvme.rsp_dma)); + cmd_pkt->dsd[1].length = nvme->u.nvme.rsp_len; + put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address); return rval; } @@ -3737,7 +3680,7 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, struct cmd_bidir *cmd_pkt, uint32_t tot_dsds) { uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; uint32_t req_data_len = 0; uint32_t rsp_data_len = 0; struct scatterlist *sg; @@ -3746,8 +3689,7 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, struct bsg_job *bsg_job = sp->u.bsg_job; /*Update entry type to indicate bidir command */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - cpu_to_le32(COMMAND_BIDIRECTIONAL); + put_unaligned_le32(COMMAND_BIDIRECTIONAL, &cmd_pkt->entry_type); /* Set the transfer direction, in this set both flags * Also set the BD_WRAP_BACK flag, firmware will take care @@ -3773,13 +3715,12 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, * are bundled in continuation iocb */ avail_dsds = 1; - cur_dsd = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; + cur_dsd = &cmd_pkt->fcp_dsd; index = 0; for_each_sg(bsg_job->request_payload.sg_list, sg, bsg_job->request_payload.sg_cnt, index) { - dma_addr_t sle_dma; cont_a64_entry_t *cont_pkt; /* Allocate additional continuation packets */ @@ -3788,14 +3729,11 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, * 5 DSDS */ cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + cur_dsd = cont_pkt->dsd; avail_dsds = 5; entry_count++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } /* For read request DSD will always goes to continuation IOCB @@ -3805,7 +3743,6 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, */ for_each_sg(bsg_job->reply_payload.sg_list, sg, bsg_job->reply_payload.sg_cnt, index) { - dma_addr_t sle_dma; cont_a64_entry_t *cont_pkt; /* Allocate additional continuation packets */ @@ -3814,14 +3751,11 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, * 5 DSDS */ cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + cur_dsd = cont_pkt->dsd; avail_dsds = 5; entry_count++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } /* This value should be same as number of IOCB required for this cmd */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 69bbea9239cc..78aec50abe0f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -23,6 +23,14 @@ static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *); static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, sts_entry_t *); +const char *const port_state_str[] = { + "Unknown", + "UNCONFIGURED", + "DEAD", + "LOST", + "ONLINE" +}; + /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. * @irq: interrupt number @@ -41,7 +49,7 @@ qla2100_intr_handler(int irq, void *dev_id) int status; unsigned long iter; uint16_t hccr; - uint16_t mb[4]; + uint16_t mb[8]; struct rsp_que *rsp; unsigned long flags; @@ -160,7 +168,7 @@ qla2300_intr_handler(int irq, void *dev_id) unsigned long iter; uint32_t stat; uint16_t hccr; - uint16_t mb[4]; + uint16_t mb[8]; struct rsp_que *rsp; struct qla_hw_data *ha; unsigned long flags; @@ -366,7 +374,7 @@ qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed) static const char *const link_speeds[] = { "1", "2", "?", "4", "8", "16", "32", "10" }; -#define QLA_LAST_SPEED 7 +#define QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1) if (IS_QLA2100(ha) || IS_QLA2200(ha)) return link_speeds[0]; @@ -708,12 +716,15 @@ skip_rio: break; case MBA_SYSTEM_ERR: /* System Error */ - mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ? + mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) ? RD_REG_WORD(®24->mailbox7) : 0; ql_log(ql_log_warn, vha, 0x5003, "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh " "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx); - + ha->fw_dump_mpi = + (IS_QLA27XX(ha) || IS_QLA28XX(ha)) && + RD_REG_WORD(®24->mailbox7) & BIT_8; ha->isp_ops->fw_dump(vha, 1); ha->flags.fw_init_done = 0; QLA_FW_STOPPED(ha); @@ -837,6 +848,7 @@ skip_rio: if (ha->flags.fawwpn_enabled && (ha->current_topology == ISP_CFG_F)) { void *wwpn = ha->init_cb->port_name; + memcpy(vha->port_name, wwpn, WWN_SIZE); fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); @@ -1372,7 +1384,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(mbx->status_flags)); ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029, - (uint8_t *)mbx, sizeof(*mbx)); + mbx, sizeof(*mbx)); goto logio_done; } @@ -1516,7 +1528,7 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req, bsg_reply->reply_payload_rcv_len = 0; } ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035, - (uint8_t *)pkt, sizeof(*pkt)); + pkt, sizeof(*pkt)); } else { res = DID_OK << 16; bsg_reply->reply_payload_rcv_len = @@ -1591,8 +1603,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, } comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status); - fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1); - fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2); + fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1); + fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2); if (iocb_type == ELS_IOCB_TYPE) { els = &sp->u.iocb_cmd; @@ -1613,7 +1625,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, res = DID_ERROR << 16; } } - ql_log(ql_log_info, vha, 0x503f, + ql_dbg(ql_dbg_user, vha, 0x503f, "ELS IOCB Done -%s error hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n", type, sp->handle, comp_status, fw_status[1], fw_status[2], le16_to_cpu(((struct els_sts_entry_24xx *) @@ -1656,7 +1668,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply), fw_status, sizeof(fw_status)); ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056, - (uint8_t *)pkt, sizeof(*pkt)); + pkt, sizeof(*pkt)); } else { res = DID_OK << 16; @@ -1700,7 +1712,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, fcport->d_id.b.area, fcport->d_id.b.al_pa, logio->entry_status); ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d, - (uint8_t *)logio, sizeof(*logio)); + logio, sizeof(*logio)); goto logio_done; } @@ -1846,8 +1858,8 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) } if (iocb->u.tmf.data != QLA_SUCCESS) - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055, - (uint8_t *)sts, sizeof(*sts)); + ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055, + sts, sizeof(*sts)); sp->done(sp, 0); } @@ -1969,6 +1981,52 @@ static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req, sp->done(sp, rval); } +/* Process a single response queue entry. */ +static void qla2x00_process_response_entry(struct scsi_qla_host *vha, + struct rsp_que *rsp, + sts_entry_t *pkt) +{ + sts21_entry_t *sts21_entry; + sts22_entry_t *sts22_entry; + uint16_t handle_cnt; + uint16_t cnt; + + switch (pkt->entry_type) { + case STATUS_TYPE: + qla2x00_status_entry(vha, rsp, pkt); + break; + case STATUS_TYPE_21: + sts21_entry = (sts21_entry_t *)pkt; + handle_cnt = sts21_entry->handle_count; + for (cnt = 0; cnt < handle_cnt; cnt++) + qla2x00_process_completed_request(vha, rsp->req, + sts21_entry->handle[cnt]); + break; + case STATUS_TYPE_22: + sts22_entry = (sts22_entry_t *)pkt; + handle_cnt = sts22_entry->handle_count; + for (cnt = 0; cnt < handle_cnt; cnt++) + qla2x00_process_completed_request(vha, rsp->req, + sts22_entry->handle[cnt]); + break; + case STATUS_CONT_TYPE: + qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); + break; + case MBX_IOCB_TYPE: + qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt); + break; + case CT_IOCB_TYPE: + qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); + break; + default: + /* Type Not Supported. */ + ql_log(ql_log_warn, vha, 0x504a, + "Received unknown response pkt type %x entry status=%x.\n", + pkt->entry_type, pkt->entry_status); + break; + } +} + /** * qla2x00_process_response_queue() - Process response queue entries. * @rsp: response queue @@ -1980,8 +2038,6 @@ qla2x00_process_response_queue(struct rsp_que *rsp) struct qla_hw_data *ha = rsp->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; sts_entry_t *pkt; - uint16_t handle_cnt; - uint16_t cnt; vha = pci_get_drvdata(ha->pdev); @@ -2006,42 +2062,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp) continue; } - switch (pkt->entry_type) { - case STATUS_TYPE: - qla2x00_status_entry(vha, rsp, pkt); - break; - case STATUS_TYPE_21: - handle_cnt = ((sts21_entry_t *)pkt)->handle_count; - for (cnt = 0; cnt < handle_cnt; cnt++) { - qla2x00_process_completed_request(vha, rsp->req, - ((sts21_entry_t *)pkt)->handle[cnt]); - } - break; - case STATUS_TYPE_22: - handle_cnt = ((sts22_entry_t *)pkt)->handle_count; - for (cnt = 0; cnt < handle_cnt; cnt++) { - qla2x00_process_completed_request(vha, rsp->req, - ((sts22_entry_t *)pkt)->handle[cnt]); - } - break; - case STATUS_CONT_TYPE: - qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); - break; - case MBX_IOCB_TYPE: - qla2x00_mbx_iocb_entry(vha, rsp->req, - (struct mbx_entry *)pkt); - break; - case CT_IOCB_TYPE: - qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); - break; - default: - /* Type Not Supported. */ - ql_log(ql_log_warn, vha, 0x504a, - "Received unknown response pkt type %x " - "entry status=%x.\n", - pkt->entry_type, pkt->entry_status); - break; - } + qla2x00_process_response_entry(vha, rsp, pkt); ((response_t *)pkt)->signature = RESPONSE_PROCESSED; wmb(); } @@ -2238,6 +2259,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, struct fc_bsg_reply *bsg_reply; sts_entry_t *sts; struct sts_entry_24xx *sts24; + sts = (sts_entry_t *) pkt; sts24 = (struct sts_entry_24xx *) pkt; @@ -3014,7 +3036,8 @@ process_err: qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); break; case ABTS_RECV_24XX: - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { /* ensure that the ATIO queue is empty */ qlt_handle_abts_recv(vha, rsp, (response_t *)pkt); @@ -3072,6 +3095,7 @@ process_err: /* Adjust ring index */ if (IS_P3P_TYPE(ha)) { struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; + WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index); } else { WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); @@ -3087,7 +3111,7 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return; rval = QLA_SUCCESS; @@ -3475,7 +3499,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) ql_log(ql_log_fatal, vha, 0x00c8, "Failed to allocate memory for ha->msix_entries.\n"); ret = -ENOMEM; - goto msix_out; + goto free_irqs; } ha->flags.msix_enabled = 1; @@ -3539,7 +3563,7 @@ msix_register_fail: } /* Enable MSI-X vector for response queue update for queue 0 */ - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { if (ha->msixbase && ha->mqiobase && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1 || ql2xmqsupport)) @@ -3558,6 +3582,10 @@ msix_register_fail: msix_out: return ret; + +free_irqs: + pci_free_irq_vectors(ha->pdev); + goto msix_out; } int @@ -3570,7 +3598,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) /* If possible, enable MSI-X. */ if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && - !IS_QLAFX00(ha) && !IS_QLA27XX(ha))) + !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))) goto skip_msi; if (ql2xenablemsix == 2) @@ -3609,7 +3637,7 @@ skip_msix: if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) goto skip_msi; ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 5400696e1f6b..133f5f6270ff 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -567,9 +567,9 @@ mbx_done: mcp->mb[0]); } else if (rval) { if (ql2xextended_error_logging & (ql_dbg_disc|ql_dbg_mbx)) { - pr_warn("%s [%s]-%04x:%ld: **** Failed", QL_MSGHDR, + pr_warn("%s [%s]-%04x:%ld: **** Failed=%x", QL_MSGHDR, dev_name(&ha->pdev->dev), 0x1020+0x800, - vha->host_no); + vha->host_no, rval); mboxes = mcp->in_mb; cnt = 4; for (i = 0; i < ha->mbx_count && cnt; i++, mboxes >>= 1) @@ -634,14 +634,15 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, mcp->out_mb |= MBX_4; } - mcp->in_mb = MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1023, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); + "Failed=%x mb[0]=%x mb[1]=%x.\n", + rval, mcp->mb[0], mcp->mb[1]); } else { ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1024, "Done %s.\n", __func__); @@ -656,7 +657,7 @@ static inline uint16_t qla25xx_set_sfp_lr_dist(struct qla_hw_data *ha) { uint16_t mb4 = BIT_0; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mb4 |= ha->long_range_distance << LR_DIST_FW_POS; return mb4; @@ -666,7 +667,7 @@ static inline uint16_t qla25xx_set_nvr_lr_dist(struct qla_hw_data *ha) { uint16_t mb4 = BIT_0; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { struct nvram_81xx *nv = ha->nvram; mb4 |= LR_DIST_FW_FIELD(nv->enhanced_features); @@ -711,7 +712,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mcp->mb[4] = 0; ha->flags.using_lr_setting = 0; if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || - IS_QLA27XX(ha)) { + IS_QLA27XX(ha) || IS_QLA28XX(ha)) { if (ql2xautodetectsfp) { if (ha->flags.detected_lr_sfp) { mcp->mb[4] |= @@ -730,19 +731,20 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) } } - if (ql2xnvmeenable && IS_QLA27XX(ha)) + if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha))) mcp->mb[4] |= NVME_ENABLE_FLAG; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { struct nvram_81xx *nv = ha->nvram; /* set minimum speed if specified in nvram */ - if (nv->min_link_speed >= 2 && - nv->min_link_speed <= 5) { + if (nv->min_supported_speed >= 2 && + nv->min_supported_speed <= 5) { mcp->mb[4] |= BIT_4; - mcp->mb[11] = nv->min_link_speed; + mcp->mb[11] |= nv->min_supported_speed & 0xF; mcp->out_mb |= MBX_11; mcp->in_mb |= BIT_5; - vha->min_link_speed_feat = nv->min_link_speed; + vha->min_supported_speed = + nv->min_supported_speed; } } @@ -770,34 +772,39 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1026, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - if (IS_FWI2_CAPABLE(ha)) { - ha->fw_ability_mask = mcp->mb[3] << 16 | mcp->mb[2]; - ql_dbg(ql_dbg_mbx, vha, 0x119a, - "fw_ability_mask=%x.\n", ha->fw_ability_mask); - ql_dbg(ql_dbg_mbx, vha, 0x1027, - "exchanges=%x.\n", mcp->mb[1]); - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { - ha->max_speed_sup = mcp->mb[2] & BIT_0; - ql_dbg(ql_dbg_mbx, vha, 0x119b, - "Maximum speed supported=%s.\n", - ha->max_speed_sup ? "32Gps" : "16Gps"); - if (vha->min_link_speed_feat) { - ha->min_link_speed = mcp->mb[5]; - ql_dbg(ql_dbg_mbx, vha, 0x119c, - "Minimum speed set=%s.\n", - mcp->mb[5] == 5 ? "32Gps" : - mcp->mb[5] == 4 ? "16Gps" : - mcp->mb[5] == 3 ? "8Gps" : - mcp->mb[5] == 2 ? "4Gps" : - "unknown"); - } - } + return rval; + } + + if (!IS_FWI2_CAPABLE(ha)) + goto done; + + ha->fw_ability_mask = mcp->mb[3] << 16 | mcp->mb[2]; + ql_dbg(ql_dbg_mbx, vha, 0x119a, + "fw_ability_mask=%x.\n", ha->fw_ability_mask); + ql_dbg(ql_dbg_mbx, vha, 0x1027, "exchanges=%x.\n", mcp->mb[1]); + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + ha->max_supported_speed = mcp->mb[2] & (BIT_0|BIT_1); + ql_dbg(ql_dbg_mbx, vha, 0x119b, "max_supported_speed=%s.\n", + ha->max_supported_speed == 0 ? "16Gps" : + ha->max_supported_speed == 1 ? "32Gps" : + ha->max_supported_speed == 2 ? "64Gps" : "unknown"); + if (vha->min_supported_speed) { + ha->min_supported_speed = mcp->mb[5] & + (BIT_0 | BIT_1 | BIT_2); + ql_dbg(ql_dbg_mbx, vha, 0x119c, + "min_supported_speed=%s.\n", + ha->min_supported_speed == 6 ? "64Gps" : + ha->min_supported_speed == 5 ? "32Gps" : + ha->min_supported_speed == 4 ? "16Gps" : + ha->min_supported_speed == 3 ? "8Gps" : + ha->min_supported_speed == 2 ? "4Gps" : "unknown"); } - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028, - "Done.\n"); } +done: + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028, + "Done %s.\n", __func__); + return rval; } @@ -1053,10 +1060,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8; if (IS_FWI2_CAPABLE(ha)) mcp->in_mb |= MBX_17|MBX_16|MBX_15; - if (IS_QLA27XX(ha)) + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->in_mb |= MBX_25|MBX_24|MBX_23|MBX_22|MBX_21|MBX_20|MBX_19|MBX_18| - MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8; + MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7; mcp->flags = 0; mcp->tov = MBX_TOV_SECONDS; @@ -1122,7 +1129,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) } } - if (IS_QLA27XX(ha)) { + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + ha->serdes_version[0] = mcp->mb[7] & 0xff; + ha->serdes_version[1] = mcp->mb[8] >> 8; + ha->serdes_version[2] = mcp->mb[8] & 0xff; ha->mpi_version[0] = mcp->mb[10] & 0xff; ha->mpi_version[1] = mcp->mb[11] >> 8; ha->mpi_version[2] = mcp->mb[11] & 0xff; @@ -1133,6 +1143,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20]; ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22]; ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24]; + if (IS_QLA28XX(ha)) { + if (mcp->mb[16] & BIT_10) { + ql_log(ql_log_info, vha, 0xffff, + "FW support secure flash updates\n"); + ha->flags.secure_fw = 1; + } + } } failed: @@ -1638,7 +1655,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10; if (IS_FWI2_CAPABLE(vha->hw)) mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16; - if (IS_QLA27XX(vha->hw)) + if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) mcp->in_mb |= MBX_15; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; @@ -1692,7 +1709,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, } } - if (IS_QLA27XX(vha->hw)) + if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) vha->bbcr = mcp->mb[15]; } @@ -1808,7 +1825,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) } /* 1 and 2 should normally be captured. */ mcp->in_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) /* mb3 is additional info about the installed SFP. */ mcp->in_mb |= MBX_3; mcp->buf_size = size; @@ -1819,10 +1836,20 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) if (rval != QLA_SUCCESS) { /*EMPTY*/ ql_dbg(ql_dbg_mbx, vha, 0x104d, - "Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x,.\n", + "Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]); + if (ha->init_cb) { + ql_dbg(ql_dbg_mbx, vha, 0x104d, "init_cb:\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, + 0x0104d, ha->init_cb, sizeof(*ha->init_cb)); + } + if (ha->ex_init_cb && ha->ex_init_cb->ex_version) { + ql_dbg(ql_dbg_mbx, vha, 0x104d, "ex_init_cb:\n"); + ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, + 0x0104d, ha->ex_init_cb, sizeof(*ha->ex_init_cb)); + } } else { - if (IS_QLA27XX(ha)) { + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { if (mcp->mb[2] == 6 || mcp->mb[3] == 2) ql_dbg(ql_dbg_mbx, vha, 0x119d, "Invalid SFP/Validation Failed\n"); @@ -2006,7 +2033,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) /* Passback COS information. */ fcport->supported_classes = (pd->options & BIT_4) ? - FC_COS_CLASS2: FC_COS_CLASS3; + FC_COS_CLASS2 : FC_COS_CLASS3; } gpd_error_out: @@ -2076,7 +2103,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) /*EMPTY*/ ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval); } else { - if (IS_QLA27XX(ha)) { + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { if (mcp->mb[2] == 6 || mcp->mb[3] == 2) ql_dbg(ql_dbg_mbx, vha, 0x119e, "Invalid SFP/Validation Failed\n"); @@ -2859,7 +2886,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha) mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; mcp->out_mb = MBX_0; mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) || IS_QLA27XX(vha->hw)) + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || + IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->in_mb |= MBX_12; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; @@ -2884,7 +2912,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha) ha->orig_fw_iocb_count = mcp->mb[10]; if (ha->flags.npiv_supported) ha->max_npiv_vports = mcp->mb[11]; - if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) ha->fw_max_fcf_count = mcp->mb[12]; } @@ -3248,7 +3277,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, /* Issue marker IOCB. */ rval2 = qla2x00_marker(vha, ha->base_qpair, fcport->loop_id, l, - type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); + type == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); if (rval2 != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1099, "Failed to issue marker IOCB (%x).\n", rval2); @@ -3323,7 +3352,7 @@ qla2x00_write_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t data) mbx_cmd_t *mcp = &mc; if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) && - !IS_QLA27XX(vha->hw)) + !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1182, @@ -3362,7 +3391,7 @@ qla2x00_read_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t *data) mbx_cmd_t *mcp = &mc; if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) && - !IS_QLA27XX(vha->hw)) + !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1185, @@ -3631,7 +3660,8 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma, "Entered %s.\n", __func__); if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) && - !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw)) + !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && + !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; if (unlikely(pci_channel_offline(vha->hw->pdev))) @@ -3744,7 +3774,7 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, rval = qla2x00_mailbox_command(vha, mcp); /* Return mailbox statuses. */ - if (mb != NULL) { + if (mb) { mb[0] = mcp->mb[0]; mb[1] = mcp->mb[1]; mb[3] = mcp->mb[3]; @@ -3779,7 +3809,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, mcp->mb[0] = MBC_PORT_PARAMS; mcp->mb[1] = loop_id; mcp->mb[2] = BIT_0; - mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0); + mcp->mb[3] = port_speed & 0x3F; mcp->mb[9] = vha->vp_idx; mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_3|MBX_1|MBX_0; @@ -3788,7 +3818,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, rval = qla2x00_mailbox_command(vha, mcp); /* Return mailbox statuses. */ - if (mb != NULL) { + if (mb) { mb[0] = mcp->mb[0]; mb[1] = mcp->mb[1]; mb[3] = mcp->mb[3]; @@ -4230,7 +4260,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111c, "Dump of Verify Request.\n"); ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111e, - (uint8_t *)mn, sizeof(*mn)); + mn, sizeof(*mn)); rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); if (rval != QLA_SUCCESS) { @@ -4242,7 +4272,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1110, "Dump of Verify Response.\n"); ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1118, - (uint8_t *)mn, sizeof(*mn)); + mn, sizeof(*mn)); status[0] = le16_to_cpu(mn->p.rsp.comp_status); status[1] = status[0] == CS_VCS_CHIP_FAILURE ? @@ -4318,7 +4348,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) mcp->mb[12] = req->qos; mcp->mb[11] = req->vp_idx; mcp->mb[13] = req->rid; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->mb[15] = 0; mcp->mb[4] = req->id; @@ -4332,9 +4362,10 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) mcp->flags = MBX_DMA_OUT; mcp->tov = MBX_TOV_SECONDS * 2; - if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) mcp->in_mb |= MBX_1; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { mcp->out_mb |= MBX_15; /* debug q create issue in SR-IOV */ mcp->in_mb |= MBX_9 | MBX_8 | MBX_7; @@ -4343,7 +4374,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) spin_lock_irqsave(&ha->hardware_lock, flags); if (!(req->options & BIT_0)) { WRT_REG_DWORD(req->req_q_in, 0); - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) WRT_REG_DWORD(req->req_q_out, 0); } spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -4387,7 +4418,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) mcp->mb[5] = rsp->length; mcp->mb[14] = rsp->msix->entry; mcp->mb[13] = rsp->rid; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->mb[15] = 0; mcp->mb[4] = rsp->id; @@ -4404,7 +4435,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) if (IS_QLA81XX(ha)) { mcp->out_mb |= MBX_12|MBX_11|MBX_10; mcp->in_mb |= MBX_1; - } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10; mcp->in_mb |= MBX_1; /* debug q create issue in SR-IOV */ @@ -4414,7 +4445,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) spin_lock_irqsave(&ha->hardware_lock, flags); if (!(rsp->options & BIT_0)) { WRT_REG_DWORD(rsp->rsp_q_out, 0); - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) WRT_REG_DWORD(rsp->rsp_q_in, 0); } @@ -4472,7 +4503,7 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size) "Entered %s.\n", __func__); if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) && - !IS_QLA27XX(vha->hw)) + !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; @@ -4504,7 +4535,7 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable) mbx_cmd_t *mcp = &mc; if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) && - !IS_QLA27XX(vha->hw)) + !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10df, @@ -4539,7 +4570,7 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) mbx_cmd_t *mcp = &mc; if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) && - !IS_QLA27XX(vha->hw)) + !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2, @@ -4570,6 +4601,42 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) } int +qla81xx_fac_semaphore_access(scsi_qla_host_t *vha, int lock) +{ + int rval = QLA_SUCCESS; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return rval; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; + mcp->mb[1] = (lock ? FAC_OPT_CMD_LOCK_SEMAPHORE : + FAC_OPT_CMD_UNLOCK_SEMAPHORE); + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x10e3, + "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", + rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e4, + "Done %s.\n", __func__); + } + + return rval; +} + +int qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) { int rval = 0; @@ -4818,10 +4885,10 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x10e9, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - if (mcp->mb[0] == MBS_COMMAND_ERROR && - mcp->mb[1] == 0x22) + if (mcp->mb[0] == MBS_COMMAND_ERROR && mcp->mb[1] == 0x22) { /* sfp is not there */ rval = QLA_INTERFACE_ERROR; + } } else { ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea, "Done %s.\n", __func__); @@ -5161,13 +5228,14 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) mcp->mb[3] = MSW(data); mcp->mb[8] = MSW(risc_addr); mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1101, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); + "Failed=%x mb[0]=%x mb[1]=%x.\n", + rval, mcp->mb[0], mcp->mb[1]); } else { ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1102, "Done %s.\n", __func__); @@ -5278,7 +5346,7 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode) mcp->out_mb = MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->in_mb |= MBX_4|MBX_3; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; @@ -5316,7 +5384,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) mcp->mb[1] = QLA_GET_DATA_RATE; mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) mcp->in_mb |= MBX_3; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; @@ -5346,7 +5414,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb) "Entered %s.\n", __func__); if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha) && - !IS_QLA27XX(ha)) + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return QLA_FUNCTION_FAILED; mcp->mb[0] = MBC_GET_PORT_CONFIG; mcp->out_mb = MBX_0; @@ -5662,6 +5730,7 @@ qla8044_md_get_template(scsi_qla_host_t *vha) mbx_cmd_t *mcp = &mc; int rval = QLA_FUNCTION_FAILED; int offset = 0, size = MINIDUMP_SIZE_36K; + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11f, "Entered %s.\n", __func__); @@ -5842,7 +5911,7 @@ qla83xx_wr_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1130, @@ -5917,7 +5986,7 @@ qla83xx_rd_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t *data) struct qla_hw_data *ha = vha->hw; unsigned long retry_max_time = jiffies + (2 * HZ); - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx, vha, 0x114b, "Entered %s.\n", __func__); @@ -5967,7 +6036,7 @@ qla83xx_restart_nic_firmware(scsi_qla_host_t *vha) mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__); @@ -6101,7 +6170,8 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, mbx_cmd_t *mcp = &mc; dma_addr_t dd_dma; - if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw)) + if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && + !IS_QLA28XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x119f, @@ -6318,7 +6388,13 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->d_id.b.rsvd_1 = 0; if (fcport->fc4f_nvme) { - fcport->port_type = FCT_NVME; + fcport->port_type = 0; + if ((pd->prli_svc_param_word_3[0] & BIT_5) == 0) + fcport->port_type |= FCT_NVME_INITIATOR; + if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) + fcport->port_type |= FCT_NVME_TARGET; + if ((pd->prli_svc_param_word_3[0] & BIT_3) == 0) + fcport->port_type |= FCT_NVME_DISCOVERY; } else { /* If not target must be initiator or unknown type. */ if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) @@ -6507,3 +6583,101 @@ int qla24xx_res_count_wait(struct scsi_qla_host *vha, done: return rval; } + +int qla28xx_secure_flash_update(scsi_qla_host_t *vha, uint16_t opts, + uint16_t region, uint32_t len, dma_addr_t sfub_dma_addr, + uint32_t sfub_len) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + mcp->mb[0] = MBC_SECURE_FLASH_UPDATE; + mcp->mb[1] = opts; + mcp->mb[2] = region; + mcp->mb[3] = MSW(len); + mcp->mb[4] = LSW(len); + mcp->mb[5] = MSW(sfub_dma_addr); + mcp->mb[6] = LSW(sfub_dma_addr); + mcp->mb[7] = MSW(MSD(sfub_dma_addr)); + mcp->mb[8] = LSW(MSD(sfub_dma_addr)); + mcp->mb[9] = sfub_len; + mcp->out_mb = + MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s(%ld): failed rval 0x%x, %x %x %x", + __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1], + mcp->mb[2]); + } + + return rval; +} + +int qla2xxx_write_remote_register(scsi_qla_host_t *vha, uint32_t addr, + uint32_t data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_WRITE_REMOTE_REG; + mcp->mb[1] = LSW(addr); + mcp->mb[2] = MSW(addr); + mcp->mb[3] = LSW(data); + mcp->mb[4] = MSW(data); + mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x10e9, + "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea, + "Done %s.\n", __func__); + } + + return rval; +} + +int qla2xxx_read_remote_register(scsi_qla_host_t *vha, uint32_t addr, + uint32_t *data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_READ_REMOTE_REG; + mcp->mb[1] = LSW(addr); + mcp->mb[2] = MSW(addr); + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + *data = (uint32_t)((((uint32_t)mcp->mb[4]) << 16) | mcp->mb[3]); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x10e9, + "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea, + "Done %s.\n", __func__); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 099d8e9851cb..b2977e49356b 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -905,7 +905,8 @@ static void qla_ctrlvp_sp_done(void *s, int res) { struct srb *sp = s; - complete(&sp->comp); + if (sp->comp) + complete(sp->comp); /* don't free sp here. Let the caller do the free */ } @@ -922,6 +923,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) struct qla_hw_data *ha = vha->hw; int vp_index = vha->vp_idx; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + DECLARE_COMPLETION_ONSTACK(comp); srb_t *sp; ql_dbg(ql_dbg_vport, vha, 0x10c1, @@ -936,6 +938,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) sp->type = SRB_CTRL_VP; sp->name = "ctrl_vp"; + sp->comp = ∁ sp->done = qla_ctrlvp_sp_done; sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); @@ -953,7 +956,9 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) ql_dbg(ql_dbg_vport, vha, 0x113f, "%s hndl %x submitted\n", sp->name, sp->handle); - wait_for_completion(&sp->comp); + wait_for_completion(&comp); + sp->comp = NULL; + rval = sp->rc; switch (rval) { case QLA_FUNCTION_TIMEOUT: diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 60f964c53c01..942ee13b96a4 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -273,9 +273,9 @@ premature_exit: if (rval) { ql_log(ql_log_warn, base_vha, 0x1163, - "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, " - "mb[3]=%x, cmd=%x ****.\n", - mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command); + "**** Failed=%x mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n", + rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], + command); } else { ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__); } @@ -629,17 +629,20 @@ qlafx00_soc_cpu_reset(scsi_qla_host_t *vha) * * Returns 0 on success. */ -void +int qlafx00_soft_reset(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; + int rval = QLA_FUNCTION_FAILED; if (unlikely(pci_channel_offline(ha->pdev) && ha->flags.pci_channel_io_perm_failure)) - return; + return rval; ha->isp_ops->disable_intrs(ha); qlafx00_soc_cpu_reset(vha); + + return QLA_SUCCESS; } /** @@ -1138,8 +1141,8 @@ qlafx00_find_all_targets(scsi_qla_host_t *vha, ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088, "Listing Target bit map...\n"); - ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha, - 0x2089, (uint8_t *)ha->gid_list, 32); + ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha, 0x2089, + ha->gid_list, 32); /* Allocate temporary rmtport for any new rmtports discovered. */ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); @@ -1320,6 +1323,7 @@ qlafx00_configure_devices(scsi_qla_host_t *vha) { int rval; unsigned long flags; + rval = QLA_SUCCESS; flags = vha->dpc_flags; @@ -1913,8 +1917,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) phost_info->domainname, phost_info->hostdriver); ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d, - (uint8_t *)phost_info, - sizeof(struct host_system_info)); + phost_info, sizeof(*phost_info)); } } @@ -1968,7 +1971,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) vha->d_id.b.al_pa = pinfo->port_id[2]; qlafx00_update_host_attr(vha, pinfo); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141, - (uint8_t *)pinfo, 16); + pinfo, 16); } else if (fx_type == FXDISC_GET_TGT_NODE_INFO) { struct qlafx00_tgt_node_info *pinfo = (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr; @@ -1976,12 +1979,12 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE); fcport->port_type = FCT_TARGET; ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144, - (uint8_t *)pinfo, 16); + pinfo, 16); } else if (fx_type == FXDISC_GET_TGT_NODE_LIST) { struct qlafx00_tgt_node_info *pinfo = (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr; ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146, - (uint8_t *)pinfo, 16); + pinfo, 16); memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE); } else if (fx_type == FXDISC_ABORT_IOCTL) fdisc->u.fxiocb.result = @@ -2248,18 +2251,16 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req, fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply); - memcpy(fw_sts_ptr, (uint8_t *)&fstatus, - sizeof(struct qla_mt_iocb_rsp_fx00)); + memcpy(fw_sts_ptr, &fstatus, sizeof(fstatus)); bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t); ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, - sp->fcport->vha, 0x5080, - (uint8_t *)pkt, sizeof(struct ioctl_iocb_entry_fx00)); + sp->vha, 0x5080, pkt, sizeof(*pkt)); ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, - sp->fcport->vha, 0x5074, - (uint8_t *)fw_sts_ptr, sizeof(struct qla_mt_iocb_rsp_fx00)); + sp->vha, 0x5074, + fw_sts_ptr, sizeof(fstatus)); res = bsg_reply->result = DID_OK << 16; bsg_reply->reply_payload_rcv_len = @@ -2597,7 +2598,7 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) /* Move sense data. */ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e, - (uint8_t *)pkt, sizeof(sts_cont_entry_t)); + pkt, sizeof(*pkt)); memcpy(sense_ptr, pkt->data, sense_sz); ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a, sense_ptr, sense_sz); @@ -2992,7 +2993,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt, uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt) { uint16_t avail_dsds; - __le32 *cur_dsd; + struct dsd64 *cur_dsd; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; struct scatterlist *sg; @@ -3028,12 +3029,10 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt, /* One DSD is available in the Command Type 3 IOCB */ avail_dsds = 1; - cur_dsd = (__le32 *)&lcmd_pkt->dseg_0_address; + cur_dsd = &lcmd_pkt->dsd; /* Load data segments */ scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { /* @@ -3043,26 +3042,23 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt, memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE); cont_pkt = qlafx00_prep_cont_type1_iocb(req, &lcont_pkt); - cur_dsd = (__le32 *)lcont_pkt.dseg_0_address; + cur_dsd = lcont_pkt.dsd; avail_dsds = 5; cont = 1; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; if (avail_dsds == 0 && cont == 1) { cont = 0; memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt, - REQUEST_ENTRY_SIZE); + sizeof(lcont_pkt)); } } if (avail_dsds != 0 && cont == 1) { memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt, - REQUEST_ENTRY_SIZE); + sizeof(lcont_pkt)); } } @@ -3172,9 +3168,9 @@ qlafx00_start_scsi(srb_t *sp) lcmd_pkt.entry_status = (uint8_t) rsp->id; ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e, - (uint8_t *)cmd->cmnd, cmd->cmd_len); + cmd->cmnd, cmd->cmd_len); ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032, - (uint8_t *)&lcmd_pkt, REQUEST_ENTRY_SIZE); + &lcmd_pkt, sizeof(lcmd_pkt)); memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE); wmb(); @@ -3282,11 +3278,9 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) fx_iocb.req_dsdcnt = cpu_to_le16(1); fx_iocb.req_xfrcnt = cpu_to_le16(fxio->u.fxiocb.req_len); - fx_iocb.dseg_rq_address[0] = - cpu_to_le32(LSD(fxio->u.fxiocb.req_dma_handle)); - fx_iocb.dseg_rq_address[1] = - cpu_to_le32(MSD(fxio->u.fxiocb.req_dma_handle)); - fx_iocb.dseg_rq_len = + put_unaligned_le64(fxio->u.fxiocb.req_dma_handle, + &fx_iocb.dseg_rq.address); + fx_iocb.dseg_rq.length = cpu_to_le32(fxio->u.fxiocb.req_len); } @@ -3294,11 +3288,9 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) fx_iocb.rsp_dsdcnt = cpu_to_le16(1); fx_iocb.rsp_xfrcnt = cpu_to_le16(fxio->u.fxiocb.rsp_len); - fx_iocb.dseg_rsp_address[0] = - cpu_to_le32(LSD(fxio->u.fxiocb.rsp_dma_handle)); - fx_iocb.dseg_rsp_address[1] = - cpu_to_le32(MSD(fxio->u.fxiocb.rsp_dma_handle)); - fx_iocb.dseg_rsp_len = + put_unaligned_le64(fxio->u.fxiocb.rsp_dma_handle, + &fx_iocb.dseg_rsp.address); + fx_iocb.dseg_rsp.length = cpu_to_le32(fxio->u.fxiocb.rsp_len); } @@ -3308,6 +3300,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) fx_iocb.flags = fxio->u.fxiocb.flags; } else { struct scatterlist *sg; + bsg_job = sp->u.bsg_job; bsg_request = bsg_job->request; piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *) @@ -3327,19 +3320,17 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) int avail_dsds, tot_dsds; cont_a64_entry_t lcont_pkt; cont_a64_entry_t *cont_pkt = NULL; - __le32 *cur_dsd; + struct dsd64 *cur_dsd; int index = 0, cont = 0; fx_iocb.req_dsdcnt = cpu_to_le16(bsg_job->request_payload.sg_cnt); tot_dsds = bsg_job->request_payload.sg_cnt; - cur_dsd = (__le32 *)&fx_iocb.dseg_rq_address[0]; + cur_dsd = &fx_iocb.dseg_rq; avail_dsds = 1; for_each_sg(bsg_job->request_payload.sg_list, sg, tot_dsds, index) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { /* @@ -3351,17 +3342,13 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) cont_pkt = qlafx00_prep_cont_type1_iocb( sp->vha->req, &lcont_pkt); - cur_dsd = (__le32 *) - lcont_pkt.dseg_0_address; + cur_dsd = lcont_pkt.dsd; avail_dsds = 5; cont = 1; entry_cnt++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; if (avail_dsds == 0 && cont == 1) { @@ -3389,19 +3376,17 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) int avail_dsds, tot_dsds; cont_a64_entry_t lcont_pkt; cont_a64_entry_t *cont_pkt = NULL; - __le32 *cur_dsd; + struct dsd64 *cur_dsd; int index = 0, cont = 0; fx_iocb.rsp_dsdcnt = cpu_to_le16(bsg_job->reply_payload.sg_cnt); tot_dsds = bsg_job->reply_payload.sg_cnt; - cur_dsd = (__le32 *)&fx_iocb.dseg_rsp_address[0]; + cur_dsd = &fx_iocb.dseg_rsp; avail_dsds = 1; for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { - dma_addr_t sle_dma; - /* Allocate additional continuation packets? */ if (avail_dsds == 0) { /* @@ -3413,17 +3398,13 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) cont_pkt = qlafx00_prep_cont_type1_iocb( sp->vha->req, &lcont_pkt); - cur_dsd = (__le32 *) - lcont_pkt.dseg_0_address; + cur_dsd = lcont_pkt.dsd; avail_dsds = 5; cont = 1; entry_cnt++; } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; if (avail_dsds == 0 && cont == 1) { @@ -3454,10 +3435,8 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb) } ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, - sp->vha, 0x3047, - (uint8_t *)&fx_iocb, sizeof(struct fxdisc_entry_fx00)); + sp->vha, 0x3047, &fx_iocb, sizeof(fx_iocb)); - memcpy_toio((void __iomem *)pfxiocb, &fx_iocb, - sizeof(struct fxdisc_entry_fx00)); + memcpy_toio((void __iomem *)pfxiocb, &fx_iocb, sizeof(fx_iocb)); wmb(); } diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h index aeaa1b40b1fc..4567f0c42486 100644 --- a/drivers/scsi/qla2xxx/qla_mr.h +++ b/drivers/scsi/qla2xxx/qla_mr.h @@ -7,6 +7,8 @@ #ifndef __QLA_MR_H #define __QLA_MR_H +#include "qla_dsd.h" + /* * The PCI VendorID and DeviceID for our board. */ @@ -46,8 +48,7 @@ struct cmd_type_7_fx00 { uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */ __le32 byte_count; /* Total byte count. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_len; /* Data segment 0 length. */ + struct dsd64 dsd; }; #define STATUS_TYPE_FX00 0x01 /* Status entry. */ @@ -176,10 +177,8 @@ struct fxdisc_entry_fx00 { uint8_t flags; uint8_t reserved_1; - __le32 dseg_rq_address[2]; /* Data segment 0 address. */ - __le32 dseg_rq_len; /* Data segment 0 length. */ - __le32 dseg_rsp_address[2]; /* Data segment 1 address. */ - __le32 dseg_rsp_len; /* Data segment 1 length. */ + struct dsd64 dseg_rq; + struct dsd64 dseg_rsp; __le32 dataword; __le32 adapid; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 41c85da3ab32..963094b3c300 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -12,8 +12,6 @@ static struct nvme_fc_port_template qla_nvme_fc_transport; -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 qla_nvme_rport *rport; @@ -38,7 +36,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) (fcport->nvme_flag & NVME_FLAG_REGISTERED)) return 0; - INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port); fcport->nvme_flag &= ~NVME_FLAG_RESETTING; memset(&req, 0, sizeof(struct nvme_fc_port_info)); @@ -74,7 +71,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) 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; @@ -124,54 +120,91 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, return 0; } -static void qla_nvme_sp_ls_done(void *ptr, int res) +static void qla_nvme_release_fcp_cmd_kref(struct kref *kref) { - srb_t *sp = ptr; + struct srb *sp = container_of(kref, struct srb, cmd_kref); + struct nvme_private *priv = (struct nvme_private *)sp->priv; + struct nvmefc_fcp_req *fd; struct srb_iocb *nvme; - struct nvmefc_ls_req *fd; - struct nvme_private *priv; + unsigned long flags; - if (atomic_read(&sp->ref_count) == 0) { - ql_log(ql_log_warn, sp->fcport->vha, 0x2123, - "SP reference-count to ZERO on LS_done -- sp=%p.\n", sp); - return; + if (!priv) + goto out; + + nvme = &sp->u.iocb_cmd; + fd = nvme->u.nvme.desc; + + spin_lock_irqsave(&priv->cmd_lock, flags); + priv->sp = NULL; + sp->priv = NULL; + if (priv->comp_status == QLA_SUCCESS) { + fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len; + } else { + fd->rcv_rsplen = 0; + fd->transferred_length = 0; } + fd->status = 0; + spin_unlock_irqrestore(&priv->cmd_lock, flags); + + fd->done(fd); +out: + qla2xxx_rel_qpair_sp(sp->qpair, sp); +} + +static void qla_nvme_release_ls_cmd_kref(struct kref *kref) +{ + struct srb *sp = container_of(kref, struct srb, cmd_kref); + struct nvme_private *priv = (struct nvme_private *)sp->priv; + struct nvmefc_ls_req *fd; + unsigned long flags; + + if (!priv) + goto out; + + spin_lock_irqsave(&priv->cmd_lock, flags); + priv->sp = NULL; + sp->priv = NULL; + spin_unlock_irqrestore(&priv->cmd_lock, flags); + + fd = priv->fd; + fd->done(fd, priv->comp_status); +out: + qla2x00_rel_sp(sp); +} + +static void qla_nvme_ls_complete(struct work_struct *work) +{ + struct nvme_private *priv = + container_of(work, struct nvme_private, ls_work); + + kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref); +} - if (!atomic_dec_and_test(&sp->ref_count)) +static void qla_nvme_sp_ls_done(void *ptr, int res) +{ + srb_t *sp = ptr; + struct nvme_private *priv; + + if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0)) return; if (res) res = -EINVAL; - nvme = &sp->u.iocb_cmd; - fd = nvme->u.nvme.desc; - priv = fd->private; + priv = (struct nvme_private *)sp->priv; priv->comp_status = res; + INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); schedule_work(&priv->ls_work); - /* work schedule doesn't need the sp */ - qla2x00_rel_sp(sp); } +/* it assumed that QPair lock is held. */ static void qla_nvme_sp_done(void *ptr, int res) { srb_t *sp = ptr; - struct srb_iocb *nvme; - struct nvmefc_fcp_req *fd; + struct nvme_private *priv = (struct nvme_private *)sp->priv; - nvme = &sp->u.iocb_cmd; - fd = nvme->u.nvme.desc; - - if (!atomic_dec_and_test(&sp->ref_count)) - return; - - if (res == QLA_SUCCESS) - fd->status = 0; - else - fd->status = NVME_SC_INTERNAL; - - fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len; - fd->done(fd); - qla2xxx_rel_qpair_sp(sp->qpair, sp); + priv->comp_status = res; + kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref); return; } @@ -185,13 +218,20 @@ static void qla_nvme_abort_work(struct work_struct *work) struct qla_hw_data *ha = fcport->vha->hw; int rval; - if (fcport) - ql_dbg(ql_dbg_io, fcport->vha, 0xffff, - "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n", - __func__, sp, sp->handle, fcport, fcport->deleted); + ql_dbg(ql_dbg_io, fcport->vha, 0xffff, + "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n", + __func__, sp, sp->handle, fcport, fcport->deleted); if (!ha->flags.fw_started && (fcport && fcport->deleted)) - return; + goto out; + + if (ha->flags.host_shutting_down) { + ql_log(ql_log_info, sp->fcport->vha, 0xffff, + "%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n", + __func__, sp, sp->type, atomic_read(&sp->ref_count)); + sp->done(sp, 0); + goto out; + } rval = ha->isp_ops->abort_command(sp); @@ -199,25 +239,34 @@ static void qla_nvme_abort_work(struct work_struct *work) "%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); + +out: + /* kref_get was done before work was schedule. */ + kref_put(&sp->cmd_kref, sp->put_fn); } 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; + unsigned long flags; + + spin_lock_irqsave(&priv->cmd_lock, flags); + if (!priv->sp) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + + if (!kref_get_unless_zero(&priv->sp->cmd_kref)) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + spin_unlock_irqrestore(&priv->cmd_lock, flags); INIT_WORK(&priv->abort_work, qla_nvme_abort_work); schedule_work(&priv->abort_work); } -static void qla_nvme_ls_complete(struct work_struct *work) -{ - struct nvme_private *priv = - container_of(work, struct nvme_private, ls_work); - struct nvmefc_ls_req *fd = priv->fd; - - fd->done(fd, priv->comp_status); -} static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) @@ -231,8 +280,16 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, struct qla_hw_data *ha; srb_t *sp; + + if (!fcport || (fcport && fcport->deleted)) + return rval; + vha = fcport->vha; ha = vha->hw; + + if (!ha->flags.fw_started) + return rval; + /* Alloc SRB structure */ sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); if (!sp) @@ -241,11 +298,13 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, sp->type = SRB_NVME_LS; sp->name = "nvme_ls"; sp->done = qla_nvme_sp_ls_done; - atomic_set(&sp->ref_count, 1); - nvme = &sp->u.iocb_cmd; + sp->put_fn = qla_nvme_release_ls_cmd_kref; + sp->priv = (void *)priv; priv->sp = sp; + kref_init(&sp->cmd_kref); + spin_lock_init(&priv->cmd_lock); + nvme = &sp->u.iocb_cmd; priv->fd = fd; - INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); nvme->u.nvme.desc = fd; nvme->u.nvme.dir = 0; nvme->u.nvme.dl = 0; @@ -262,8 +321,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, "qla2x00_start_sp failed = %d\n", rval); - atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); + sp->priv = NULL; + priv->sp = NULL; + qla2x00_rel_sp(sp); return rval; } @@ -275,6 +336,18 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, struct nvmefc_fcp_req *fd) { struct nvme_private *priv = fd->private; + unsigned long flags; + + spin_lock_irqsave(&priv->cmd_lock, flags); + if (!priv->sp) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + if (!kref_get_unless_zero(&priv->sp->cmd_kref)) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + spin_unlock_irqrestore(&priv->cmd_lock, flags); INIT_WORK(&priv->abort_work, qla_nvme_abort_work); schedule_work(&priv->abort_work); @@ -291,7 +364,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) uint16_t req_cnt; uint16_t tot_dsds; uint16_t avail_dsds; - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; struct req_que *req = NULL; struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; @@ -340,6 +413,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) if (unlikely(!fd->sqid)) { 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(&ha->nvme_active_aen_cnt); @@ -395,25 +469,22 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) /* NVME RSP IU */ cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen); - cmd_pkt->nvme_rsp_dseg_address[0] = cpu_to_le32(LSD(fd->rspdma)); - cmd_pkt->nvme_rsp_dseg_address[1] = cpu_to_le32(MSD(fd->rspdma)); + put_unaligned_le64(fd->rspdma, &cmd_pkt->nvme_rsp_dseg_address); /* NVME CNMD IU */ cmd_pkt->nvme_cmnd_dseg_len = cpu_to_le16(fd->cmdlen); - cmd_pkt->nvme_cmnd_dseg_address[0] = cpu_to_le32(LSD(fd->cmddma)); - cmd_pkt->nvme_cmnd_dseg_address[1] = cpu_to_le32(MSD(fd->cmddma)); + cmd_pkt->nvme_cmnd_dseg_address = cpu_to_le64(fd->cmddma); cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); cmd_pkt->byte_count = cpu_to_le32(fd->payload_length); /* One DSD is available in the Command Type NVME IOCB */ avail_dsds = 1; - cur_dsd = (uint32_t *)&cmd_pkt->nvme_data_dseg_address[0]; + cur_dsd = &cmd_pkt->nvme_dsd; sgl = fd->first_sgl; /* Load data segments */ for_each_sg(sgl, sg, tot_dsds, i) { - dma_addr_t sle_dma; cont_a64_entry_t *cont_pkt; /* Allocate additional continuation packets? */ @@ -432,17 +503,14 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) req->ring_ptr++; } cont_pkt = (cont_a64_entry_t *)req->ring_ptr; - *((uint32_t *)(&cont_pkt->entry_type)) = - cpu_to_le32(CONTINUE_A64_TYPE); + put_unaligned_le32(CONTINUE_A64_TYPE, + &cont_pkt->entry_type); - cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; - avail_dsds = 5; + cur_dsd = cont_pkt->dsd; + avail_dsds = ARRAY_SIZE(cont_pkt->dsd); } - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + append_dsd64(&cur_dsd, sg); avail_dsds--; } @@ -483,11 +551,11 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, fcport = qla_rport->fcport; - vha = fcport->vha; - - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) + if (!qpair || !fcport || (qpair && !qpair->fw_started) || + (fcport && fcport->deleted)) return rval; + vha = fcport->vha; /* * 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 @@ -503,12 +571,15 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, if (!sp) return -EBUSY; - atomic_set(&sp->ref_count, 1); init_waitqueue_head(&sp->nvme_ls_waitq); + kref_init(&sp->cmd_kref); + spin_lock_init(&priv->cmd_lock); + sp->priv = (void *)priv; priv->sp = sp; sp->type = SRB_NVME_CMD; sp->name = "nvme_cmd"; sp->done = qla_nvme_sp_done; + sp->put_fn = qla_nvme_release_fcp_cmd_kref; sp->qpair = qpair; sp->vha = vha; nvme = &sp->u.iocb_cmd; @@ -518,8 +589,10 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x212d, "qla2x00_start_nvme_mq failed = %d\n", rval); - atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); + sp->priv = NULL; + priv->sp = NULL; + qla2xxx_rel_qpair_sp(sp->qpair, sp); } return rval; @@ -538,29 +611,16 @@ 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 qla_nvme_rport *qla_rport = rport->private, *trport; + struct qla_nvme_rport *qla_rport = rport->private; fcport = qla_rport->fcport; fcport->nvme_remote_port = NULL; fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; - - list_for_each_entry_safe(qla_rport, trport, - &fcport->vha->nvme_rport_list, list) { - if (qla_rport->fcport == fcport) { - list_del(&qla_rport->list); - break; - } - } - 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_DELETING; ql_log(ql_log_info, fcport->vha, 0x2110, - "remoteport_delete of %p completed.\n", fcport); + "remoteport_delete of %p %8phN completed.\n", + fcport, fcport->port_name); + complete(&fcport->nvme_del_done); } static struct nvme_fc_port_template qla_nvme_fc_transport = { @@ -573,7 +633,7 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .fcp_io = qla_nvme_post_cmd, .fcp_abort = qla_nvme_fcp_abort, .max_hw_queues = 8, - .max_sgl_segments = 128, + .max_sgl_segments = 1024, .max_dif_sgl_segments = 64, .dma_boundary = 0xFFFFFFFF, .local_priv_sz = 8, @@ -582,68 +642,25 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .fcprqst_priv_sz = sizeof(struct nvme_private), }; -#define NVME_ABORT_POLLING_PERIOD 2 -static int qla_nvme_wait_on_command(srb_t *sp) -{ - int ret = QLA_SUCCESS; - - wait_event_timeout(sp->nvme_ls_waitq, (atomic_read(&sp->ref_count) > 1), - NVME_ABORT_POLLING_PERIOD*HZ); - - if (atomic_read(&sp->ref_count) > 1) - ret = QLA_FUNCTION_FAILED; - - return ret; -} - -void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp, int res) -{ - int rval; - - if (ha->flags.fw_started) { - 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) +void qla_nvme_unregister_remote_port(struct fc_port *fcport) { - struct fc_port *fcport = container_of(work, struct fc_port, - nvme_del_work); - struct qla_nvme_rport *qla_rport, *trport; - scsi_qla_host_t *base_vha; + int ret; if (!IS_ENABLED(CONFIG_NVME_FC)) return; ql_log(ql_log_warn, NULL, 0x2112, - "%s: unregister remoteport on %p\n",__func__, fcport); - - base_vha = pci_get_drvdata(fcport->vha->hw->pdev); - if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags)) { - ql_dbg(ql_dbg_disc, fcport->vha, 0x2114, - "%s: Notify FC-NVMe transport, set devloss=0\n", - __func__); - - nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); - } - - list_for_each_entry_safe(qla_rport, trport, - &fcport->vha->nvme_rport_list, list) { - 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); - wait_for_completion(&fcport->nvme_del_done); - break; - } - } + "%s: unregister remoteport on %p %8phN\n", + __func__, fcport, fcport->port_name); + + nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); + init_completion(&fcport->nvme_del_done); + ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port); + if (ret) + ql_log(ql_log_info, fcport->vha, 0x2114, + "%s: Failed to unregister nvme_remote_port (%d)\n", + __func__, ret); + wait_for_completion(&fcport->nvme_del_done); } void qla_nvme_delete(struct scsi_qla_host *vha) diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h index da8dad5ad693..67bb4a2a3742 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.h +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -13,6 +13,7 @@ #include <linux/nvme-fc-driver.h> #include "qla_def.h" +#include "qla_dsd.h" /* default dev loss time (seconds) before transport tears down ctrl */ #define NVME_FC_DEV_LOSS_TMO 30 @@ -33,10 +34,10 @@ struct nvme_private { struct work_struct ls_work; struct work_struct abort_work; int comp_status; + spinlock_t cmd_lock; }; struct qla_nvme_rport { - struct list_head list; struct fc_port *fcport; }; @@ -64,16 +65,15 @@ struct cmd_nvme { #define CF_WRITE_DATA BIT_0 uint16_t nvme_cmnd_dseg_len; /* Data segment length. */ - uint32_t nvme_cmnd_dseg_address[2]; /* Data segment address. */ - uint32_t nvme_rsp_dseg_address[2]; /* Data segment address. */ + __le64 nvme_cmnd_dseg_address __packed;/* Data segment address. */ + __le64 nvme_rsp_dseg_address __packed; /* Data segment address. */ uint32_t byte_count; /* Total byte count. */ uint8_t port_id[3]; /* PortID of destination port. */ uint8_t vp_index; - uint32_t nvme_data_dseg_address[2]; /* Data segment address. */ - uint32_t nvme_data_dseg_len; /* Data segment length. */ + struct dsd64 nvme_dsd; }; #define PT_LS4_REQUEST 0x89 /* Link Service pass-through IOCB (request) */ @@ -101,10 +101,7 @@ struct pt_ls4_request { uint32_t rsvd3; uint32_t rx_byte_count; uint32_t tx_byte_count; - uint32_t dseg0_address[2]; - uint32_t dseg0_len; - uint32_t dseg1_address[2]; - uint32_t dseg1_len; + struct dsd64 dsd[2]; }; #define PT_LS4_UNSOL 0x56 /* pass-up unsolicited rec FC-NVMe request */ @@ -145,7 +142,6 @@ struct pt_ls4_rx_unsol { int 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, 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 f2f54806f4da..c760ae354174 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -6,6 +6,7 @@ */ #include "qla_def.h" #include <linux/delay.h> +#include <linux/io-64-nonatomic-lo-hi.h> #include <linux/pci.h> #include <linux/ratelimit.h> #include <linux/vmalloc.h> @@ -608,6 +609,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) } else if (addr_in_range(addr, QLA82XX_ADDR_OCM0, QLA82XX_ADDR_OCM0_MAX)) { unsigned int temp1; + if ((addr & 0x00ff800) == 0xff800) { ql_log(ql_log_warn, vha, 0xb004, "%s: QM access not handled.\n", __func__); @@ -990,6 +992,7 @@ static int qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR); qla82xx_wait_rom_busy(ha); if (qla82xx_wait_rom_done(ha)) { @@ -1030,6 +1033,7 @@ static int qla82xx_flash_set_write_enable(struct qla_hw_data *ha) { uint32_t val; + qla82xx_wait_rom_busy(ha); qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN); @@ -1047,6 +1051,7 @@ static int qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + if (qla82xx_flash_set_write_enable(ha)) return -1; qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val); @@ -1063,6 +1068,7 @@ static int qla82xx_write_disable_flash(struct qla_hw_data *ha) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI); if (qla82xx_wait_rom_done(ha)) { ql_log(ql_log_warn, vha, 0xb00f, @@ -1435,6 +1441,7 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha) long memaddr = BOOTLD_START; u64 data; u32 high, low; + size = (IMAGE_START - BOOTLD_START) / 8; for (i = 0; i < size; i++) { @@ -1757,11 +1764,14 @@ qla82xx_pci_config(scsi_qla_host_t *vha) * * Returns 0 on success. */ -void +int qla82xx_reset_chip(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; + ha->isp_ops->disable_intrs(ha); + + return QLA_SUCCESS; } void qla82xx_config_rings(struct scsi_qla_host *vha) @@ -1778,10 +1788,8 @@ void qla82xx_config_rings(struct scsi_qla_host *vha) icb->response_q_inpointer = cpu_to_le16(0); icb->request_q_length = cpu_to_le16(req->length); icb->response_q_length = cpu_to_le16(rsp->length); - icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); - icb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); - icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); - icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); + put_unaligned_le64(req->dma, &icb->request_q_address); + put_unaligned_le64(rsp->dma, &icb->response_q_address); WRT_REG_DWORD(®->req_q_out[0], 0); WRT_REG_DWORD(®->rsp_q_in[0], 0); @@ -1992,6 +2000,7 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) uint16_t __iomem *wptr; struct qla_hw_data *ha = vha->hw; struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; + wptr = (uint16_t __iomem *)®->mailbox_out[1]; /* Load return mailbox registers. */ @@ -2028,7 +2037,7 @@ qla82xx_intr_handler(int irq, void *dev_id) unsigned long flags; unsigned long iter; uint32_t stat = 0; - uint16_t mb[4]; + uint16_t mb[8]; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -2112,7 +2121,7 @@ qla82xx_msix_default(int irq, void *dev_id) unsigned long flags; uint32_t stat = 0; uint32_t host_int = 0; - uint16_t mb[4]; + uint16_t mb[8]; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -2208,7 +2217,7 @@ qla82xx_poll(int irq, void *dev_id) int status = 0; uint32_t stat; uint32_t host_int = 0; - uint16_t mb[4]; + uint16_t mb[8]; unsigned long flags; rsp = (struct rsp_que *) dev_id; @@ -2262,6 +2271,7 @@ void qla82xx_enable_intrs(struct qla_hw_data *ha) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + qla82xx_mbx_intr_enable(vha); spin_lock_irq(&ha->hardware_lock); if (IS_QLA8044(ha)) @@ -2276,6 +2286,7 @@ void qla82xx_disable_intrs(struct qla_hw_data *ha) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + qla82xx_mbx_intr_disable(vha); spin_lock_irq(&ha->hardware_lock); if (IS_QLA8044(ha)) @@ -2658,8 +2669,8 @@ done: /* * Address and length are byte address */ -uint8_t * -qla82xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +void * +qla82xx_read_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { scsi_block_requests(vha->host); @@ -2767,15 +2778,14 @@ write_done: } int -qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +qla82xx_write_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { int rval; /* Suspend HBA. */ scsi_block_requests(vha->host); - rval = qla82xx_write_flash_data(vha, (uint32_t *)buf, offset, - length >> 2); + rval = qla82xx_write_flash_data(vha, buf, offset, length >> 2); scsi_unblock_requests(vha->host); /* Convert return ISP82xx to generic */ @@ -4464,6 +4474,7 @@ qla82xx_beacon_on(struct scsi_qla_host *vha) int rval; struct qla_hw_data *ha = vha->hw; + qla82xx_idc_lock(ha); rval = qla82xx_mbx_beacon_ctl(vha, 1); @@ -4484,6 +4495,7 @@ qla82xx_beacon_off(struct scsi_qla_host *vha) int rval; struct qla_hw_data *ha = vha->hw; + qla82xx_idc_lock(ha); rval = qla82xx_mbx_beacon_ctl(vha, 0); diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 71a41093530e..3c7beef92c35 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -7,7 +7,7 @@ #ifndef __QLA_NX_H #define __QLA_NX_H -#include <linux/io-64-nonatomic-lo-hi.h> +#include <scsi/scsi.h> /* * Following are the states of the Phantom. Phantom will set them and diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index fe856b602e03..369ac04d0454 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -559,12 +559,12 @@ exit_lock_error: /* * Address and length are byte address */ -uint8_t * -qla8044_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +void * +qla8044_read_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { scsi_block_requests(vha->host); - if (qla8044_read_flash_data(vha, (uint8_t *)buf, offset, length / 4) + if (qla8044_read_flash_data(vha, buf, offset, length / 4) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0xb08d, "%s: Failed to read from flash\n", @@ -3007,10 +3007,9 @@ qla8044_minidump_process_rddfe(struct scsi_qla_host *vha, uint16_t count; uint32_t poll, mask, modify_mask; uint32_t wait_count = 0; - uint32_t *data_ptr = *d_ptr; - struct qla8044_minidump_entry_rddfe *rddfe; + rddfe = (struct qla8044_minidump_entry_rddfe *) entry_hdr; addr1 = rddfe->addr_1; @@ -3797,7 +3796,7 @@ qla8044_write_flash_dword_mode(scsi_qla_host_t *vha, uint32_t *dwptr, } int -qla8044_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +qla8044_write_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { int rval = QLA_FUNCTION_FAILED, i, burst_iter_count; @@ -3896,7 +3895,7 @@ qla8044_intr_handler(int irq, void *dev_id) unsigned long flags; unsigned long iter; uint32_t stat; - uint16_t mb[4]; + uint16_t mb[8]; uint32_t leg_int_ptr = 0, pf_bit; rsp = (struct rsp_que *) dev_id; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 91f576d743fe..2e58cff9d200 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -42,7 +42,7 @@ static struct kmem_cache *ctx_cachep; /* * error level for logging */ -int ql_errlev = ql_log_all; +uint ql_errlev = 0x8001; static int ql2xenableclass2; module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR); @@ -108,7 +108,7 @@ MODULE_PARM_DESC(ql2xshiftctondsd, "Set to control shifting of command type processing " "based on total number of SG elements."); -int ql2xfdmienable=1; +int ql2xfdmienable = 1; module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR); module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xfdmienable, @@ -154,7 +154,7 @@ MODULE_PARM_DESC(ql2xenablehba_err_chk, " 1 -- Error isolation enabled only for DIX Type 0\n" " 2 -- Error isolation enabled for all Types\n"); -int ql2xiidmaenable=1; +int ql2xiidmaenable = 1; module_param(ql2xiidmaenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xiidmaenable, "Enables iIDMA settings " @@ -285,14 +285,14 @@ MODULE_PARM_DESC(qla2xuseresexchforels, "Reserve 1/2 of emergency exchanges for ELS.\n" " 0 (default): disabled"); -int ql2xprotmask; +static int ql2xprotmask; module_param(ql2xprotmask, int, 0644); MODULE_PARM_DESC(ql2xprotmask, "Override DIF/DIX protection capabilities mask\n" "Default is 0 which sets protection mask based on " "capabilities reported by HBA firmware.\n"); -int ql2xprotguard; +static int ql2xprotguard; module_param(ql2xprotguard, int, 0644); MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n" " 0 -- Let HBA firmware decide\n" @@ -306,58 +306,12 @@ MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers, "0 (Default). Based on check.\n" "1 Force using internal buffers\n"); -/* - * SCSI host template entry points - */ -static int qla2xxx_slave_configure(struct scsi_device * device); -static int qla2xxx_slave_alloc(struct scsi_device *); -static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time); -static void qla2xxx_scan_start(struct Scsi_Host *); -static void qla2xxx_slave_destroy(struct scsi_device *); -static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); -static int qla2xxx_eh_abort(struct scsi_cmnd *); -static int qla2xxx_eh_device_reset(struct scsi_cmnd *); -static int qla2xxx_eh_target_reset(struct scsi_cmnd *); -static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); -static int qla2xxx_eh_host_reset(struct scsi_cmnd *); - static void qla2x00_clear_drv_active(struct qla_hw_data *); static void qla2x00_free_device(scsi_qla_host_t *); static int qla2xxx_map_queues(struct Scsi_Host *shost); static void qla2x00_destroy_deferred_work(struct qla_hw_data *); -struct scsi_host_template qla2xxx_driver_template = { - .module = THIS_MODULE, - .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla2xxx_queuecommand, - - .eh_timed_out = fc_eh_timed_out, - .eh_abort_handler = qla2xxx_eh_abort, - .eh_device_reset_handler = qla2xxx_eh_device_reset, - .eh_target_reset_handler = qla2xxx_eh_target_reset, - .eh_bus_reset_handler = qla2xxx_eh_bus_reset, - .eh_host_reset_handler = qla2xxx_eh_host_reset, - - .slave_configure = qla2xxx_slave_configure, - - .slave_alloc = qla2xxx_slave_alloc, - .slave_destroy = qla2xxx_slave_destroy, - .scan_finished = qla2xxx_scan_finished, - .scan_start = qla2xxx_scan_start, - .change_queue_depth = scsi_change_queue_depth, - .map_queues = qla2xxx_map_queues, - .this_id = -1, - .cmd_per_lun = 3, - .sg_tablesize = SG_ALL, - - .max_sectors = 0xFFFF, - .shost_attrs = qla2x00_host_attrs, - - .supported_mode = MODE_INITIATOR, - .track_queue_depth = 1, -}; - static struct scsi_transport_template *qla2xxx_transport_template = NULL; struct scsi_transport_template *qla2xxx_transport_vport_template = NULL; @@ -411,6 +365,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, struct rsp_que *rsp) { struct qla_hw_data *ha = vha->hw; + rsp->qpair = ha->base_qpair; rsp->req = req; ha->base_qpair->hw = ha; @@ -427,7 +382,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, qla_cpu_update(rsp->qpair, raw_smp_processor_id()); ha->base_qpair->pdev = ha->pdev; - if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) + if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs; } @@ -435,6 +390,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, struct rsp_que *rsp) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + ha->req_q_map = kcalloc(ha->max_req_queues, sizeof(struct req_que *), GFP_KERNEL); if (!ha->req_q_map) { @@ -726,7 +682,7 @@ qla2x00_sp_free_dma(void *ptr) } if (!ctx) - goto end; + return; if (sp->flags & SRB_CRC_CTX_DSD_VALID) { /* List assured to be having elements */ @@ -751,12 +707,6 @@ qla2x00_sp_free_dma(void *ptr) ha->gbl_dsd_avail += ctx1->dsd_use_cnt; mempool_free(ctx1, ha->ctx_mempool); } - -end: - if (sp->type != SRB_NVME_CMD && sp->type != SRB_NVME_LS) { - CMD_SP(cmd) = NULL; - qla2x00_rel_sp(sp); - } } void @@ -764,22 +714,20 @@ qla2x00_sp_compl(void *ptr, int res) { srb_t *sp = ptr; struct scsi_cmnd *cmd = GET_CMD_SP(sp); + struct completion *comp = sp->comp; - cmd->result = res; - - if (atomic_read(&sp->ref_count) == 0) { - ql_dbg(ql_dbg_io, sp->vha, 0x3015, - "SP reference-count to ZERO -- sp=%p cmd=%p.\n", - sp, GET_CMD_SP(sp)); - if (ql2xextended_error_logging & ql_dbg_io) - WARN_ON(atomic_read(&sp->ref_count) == 0); - return; - } - if (!atomic_dec_and_test(&sp->ref_count)) + if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) return; + atomic_dec(&sp->ref_count); + sp->free(sp); + cmd->result = res; + CMD_SP(cmd) = NULL; cmd->scsi_done(cmd); + if (comp) + complete(comp); + qla2x00_rel_sp(sp); } void @@ -802,7 +750,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr) } if (!ctx) - goto end; + return; if (sp->flags & SRB_CRC_CTX_DSD_VALID) { /* List assured to be having elements */ @@ -810,25 +758,8 @@ qla2xxx_qpair_sp_free_dma(void *ptr) sp->flags &= ~SRB_CRC_CTX_DSD_VALID; } - if (sp->flags & SRB_CRC_CTX_DMA_VALID) { - struct crc_context *ctx0 = ctx; - - dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma); - sp->flags &= ~SRB_CRC_CTX_DMA_VALID; - } - - if (sp->flags & SRB_FCP_CMND_DMA_VALID) { - struct ct6_dsd *ctx1 = ctx; - dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, - ctx1->fcp_cmnd_dma); - list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); - ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; - ha->gbl_dsd_avail += ctx1->dsd_use_cnt; - mempool_free(ctx1, ha->ctx_mempool); - sp->flags &= ~SRB_FCP_CMND_DMA_VALID; - } if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) { - struct crc_context *difctx = sp->u.scmd.ctx; + struct crc_context *difctx = ctx; struct dsd_dma *dif_dsd, *nxt_dsd; list_for_each_entry_safe(dif_dsd, nxt_dsd, @@ -863,9 +794,24 @@ qla2xxx_qpair_sp_free_dma(void *ptr) sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID; } -end: - CMD_SP(cmd) = NULL; - qla2xxx_rel_qpair_sp(sp->qpair, sp); + if (sp->flags & SRB_FCP_CMND_DMA_VALID) { + struct ct6_dsd *ctx1 = ctx; + + dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, + ctx1->fcp_cmnd_dma); + list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); + ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; + ha->gbl_dsd_avail += ctx1->dsd_use_cnt; + mempool_free(ctx1, ha->ctx_mempool); + sp->flags &= ~SRB_FCP_CMND_DMA_VALID; + } + + if (sp->flags & SRB_CRC_CTX_DMA_VALID) { + struct crc_context *ctx0 = ctx; + + dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma); + sp->flags &= ~SRB_CRC_CTX_DMA_VALID; + } } void @@ -873,27 +819,22 @@ qla2xxx_qpair_sp_compl(void *ptr, int res) { srb_t *sp = ptr; struct scsi_cmnd *cmd = GET_CMD_SP(sp); + struct completion *comp = sp->comp; - cmd->result = res; - - if (atomic_read(&sp->ref_count) == 0) { - ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3079, - "SP reference-count to ZERO -- sp=%p cmd=%p.\n", - sp, GET_CMD_SP(sp)); - if (ql2xextended_error_logging & ql_dbg_io) - WARN_ON(atomic_read(&sp->ref_count) == 0); - return; - } - if (!atomic_dec_and_test(&sp->ref_count)) + if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) return; + atomic_dec(&sp->ref_count); + sp->free(sp); + cmd->result = res; + CMD_SP(cmd) = NULL; cmd->scsi_done(cmd); + if (comp) + complete(comp); + qla2xxx_rel_qpair_sp(sp->qpair, sp); } -/* If we are SP1 here, we need to still take and release the host_lock as SP1 - * does not have the changes necessary to avoid taking host->host_lock. - */ static int qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) { @@ -908,7 +849,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) uint32_t tag; uint16_t hwq; - if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) { + if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)) || + WARN_ON_ONCE(!rport)) { cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } @@ -1031,7 +973,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, srb_t *sp; int rval; - rval = fc_remote_port_chkready(rport); + rval = rport ? fc_remote_port_chkready(rport) : FC_PORTSTATE_OFFLINE; if (rval) { cmd->result = rval; ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3076, @@ -1272,7 +1214,7 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) static int sp_get(struct srb *sp) { - if (!refcount_inc_not_zero((refcount_t*)&sp->ref_count)) + if (!refcount_inc_not_zero((refcount_t *)&sp->ref_count)) /* kref get fail */ return ENXIO; else @@ -1332,7 +1274,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned int id; uint64_t lun; unsigned long flags; - int rval, wait = 0; + int rval; struct qla_hw_data *ha = vha->hw; struct qla_qpair *qpair; @@ -1345,7 +1287,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) ret = fc_block_scsi_eh(cmd); if (ret != 0) return ret; - ret = SUCCESS; sp = (srb_t *) CMD_SP(cmd); if (!sp) @@ -1356,7 +1297,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return SUCCESS; spin_lock_irqsave(qpair->qp_lock_ptr, flags); - if (!CMD_SP(cmd)) { + if (sp->type != SRB_SCSI_CMD || GET_CMD_SP(sp) != cmd) { /* there's a chance an interrupt could clear the ptr as part of done & free */ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -1377,58 +1318,31 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n", vha->host_no, id, lun, sp, cmd, sp->handle); - /* Get a reference to the sp and drop the lock.*/ - rval = ha->isp_ops->abort_command(sp); - if (rval) { - if (rval == QLA_FUNCTION_PARAMETER_ERROR) - ret = SUCCESS; - else - ret = FAILED; + ql_dbg(ql_dbg_taskm, vha, 0x8003, + "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval); - ql_dbg(ql_dbg_taskm, vha, 0x8003, - "Abort command mbx failed cmd=%p, rval=%x.\n", cmd, rval); - } else { - ql_dbg(ql_dbg_taskm, vha, 0x8004, - "Abort command mbx success cmd=%p.\n", cmd); - wait = 1; - } - - spin_lock_irqsave(qpair->qp_lock_ptr, flags); - /* - * Clear the slot in the oustanding_cmds array if we can't find the - * command to reclaim the resources. - */ - if (rval == QLA_FUNCTION_PARAMETER_ERROR) - vha->req->outstanding_cmds[sp->handle] = NULL; - - /* - * sp->done will do ref_count-- - * sp_get() took an extra count above - */ - sp->done(sp, DID_RESET << 16); - - /* Did the command return during mailbox execution? */ - if (ret == FAILED && !CMD_SP(cmd)) + switch (rval) { + case QLA_SUCCESS: + /* + * The command has been aborted. That means that the firmware + * won't report a completion. + */ + sp->done(sp, DID_ABORT << 16); ret = SUCCESS; - - if (!CMD_SP(cmd)) - wait = 0; - - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - - /* Wait for the command to be returned. */ - if (wait) { - if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x8006, - "Abort handler timed out cmd=%p.\n", cmd); - ret = FAILED; - } + break; + default: + /* + * Either abort failed or abort and completion raced. Let + * the SCSI core retry the abort in the former case. + */ + ret = FAILED; + break; } ql_log(ql_log_info, vha, 0x801c, - "Abort command issued nexus=%ld:%d:%llu -- %d %x.\n", - vha->host_no, id, lun, wait, ret); + "Abort command issued nexus=%ld:%d:%llu -- %x.\n", + vha->host_no, id, lun, ret); return ret; } @@ -1804,42 +1718,34 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, __releases(qp->qp_lock_ptr) __acquires(qp->qp_lock_ptr) { + DECLARE_COMPLETION_ONSTACK(comp); scsi_qla_host_t *vha = qp->vha; struct qla_hw_data *ha = vha->hw; + int rval; - if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS) { - if (!sp_get(sp)) { - /* got sp */ - spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); - qla_nvme_abort(ha, sp, res); - spin_lock_irqsave(qp->qp_lock_ptr, *flags); - } - } else if (GET_CMD_SP(sp) && !ha->flags.eeh_busy && - !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && - !qla2x00_isp_reg_stat(ha) && sp->type == SRB_SCSI_CMD) { - /* - * Don't abort commands in adapter during EEH recovery as it's - * not accessible/responding. - * - * Get a reference to the sp and drop the lock. The reference - * ensures this sp->done() call and not the call in - * qla2xxx_eh_abort() ends the SCSI cmd (with result 'res'). - */ - if (!sp_get(sp)) { - int status; + if (sp_get(sp)) + return; - spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); - status = qla2xxx_eh_abort(GET_CMD_SP(sp)); - spin_lock_irqsave(qp->qp_lock_ptr, *flags); - /* - * Get rid of extra reference caused - * by early exit from qla2xxx_eh_abort - */ - if (status == FAST_IO_FAIL) - atomic_dec(&sp->ref_count); + if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS || + (sp->type == SRB_SCSI_CMD && !ha->flags.eeh_busy && + !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && + !qla2x00_isp_reg_stat(ha))) { + sp->comp = ∁ + spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); + rval = ha->isp_ops->abort_command(sp); + + switch (rval) { + case QLA_SUCCESS: + sp->done(sp, res); + break; + case QLA_FUNCTION_PARAMETER_ERROR: + wait_for_completion(&comp); + break; } + + spin_lock_irqsave(qp->qp_lock_ptr, *flags); + sp->comp = NULL; } - sp->done(sp, res); } static void @@ -1875,15 +1781,10 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) continue; } cmd = (struct qla_tgt_cmd *)sp; - qlt_abort_cmd_on_host_reset(cmd->vha, cmd); + cmd->aborted = 1; break; case TYPE_TGT_TMCMD: - /* - * Currently, only ABTS response gets on the - * outstanding_cmds[] - */ - ha->tgt.tgt_ops->free_mcmd( - (struct qla_tgt_mgmt_cmd *)sp); + /* Skip task management functions. */ break; default: break; @@ -2753,6 +2654,24 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->device_type |= DT_T10_PI; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; + case PCI_DEVICE_ID_QLOGIC_ISP2081: + case PCI_DEVICE_ID_QLOGIC_ISP2089: + ha->isp_type |= DT_ISP2081; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->device_type |= DT_T10_PI; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; + case PCI_DEVICE_ID_QLOGIC_ISP2281: + case PCI_DEVICE_ID_QLOGIC_ISP2289: + ha->isp_type |= DT_ISP2281; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->device_type |= DT_T10_PI; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; } if (IS_QLA82XX(ha)) @@ -2760,7 +2679,8 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) else { /* Get adapter physical port no from interrupt pin register. */ pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no); - if (IS_QLA27XX(ha)) + if (IS_QLA25XX(ha) || IS_QLA2031(ha) || + IS_QLA27XX(ha) || IS_QLA28XX(ha)) ha->port_no--; else ha->port_no = !(ha->port_no & 1); @@ -2857,7 +2777,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2071 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2271 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2261) { + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2261 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2081 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2281 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2089 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289) { bars = pci_select_bars(pdev, IORESOURCE_MEM); mem_only = 1; ql_dbg_pci(ql_dbg_init, pdev, 0x0007, @@ -2877,6 +2801,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* This may fail but that's ok */ pci_enable_pcie_error_reporting(pdev); + /* Turn off T10-DIF when FC-NVMe is enabled */ + if (ql2xnvmeenable) + ql2xenabledif = 0; + ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); if (!ha) { ql_log_pci(ql_log_fatal, pdev, 0x0009, @@ -2906,7 +2834,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Set EEH reset type to fundamental if required by hba */ if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) || - IS_QLA83XX(ha) || IS_QLA27XX(ha)) + IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) pdev->needs_freset = 1; ha->prev_topology = 0; @@ -3085,6 +3013,23 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; ha->nvram_conf_off = ~0; ha->nvram_data_off = ~0; + } else if (IS_QLA28XX(ha)) { + ha->portnum = PCI_FUNC(ha->pdev->devfn); + ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; + ha->mbx_count = MAILBOX_REGISTER_COUNT; + req_length = REQUEST_ENTRY_CNT_24XX; + rsp_length = RESPONSE_ENTRY_CNT_2300; + ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; + ha->max_loop_id = SNS_LAST_LOOP_ID_2300; + ha->init_cb_size = sizeof(struct mid_init_cb_81xx); + ha->gid_list_info_size = 8; + ha->optrom_size = OPTROM_SIZE_28XX; + ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; + ha->isp_ops = &qla27xx_isp_ops; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_28XX; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA_28XX; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; } ql_dbg_pci(ql_dbg_init, pdev, 0x001e, @@ -3250,7 +3195,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) req->req_q_out = &ha->iobase->isp24.req_q_out; rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in; rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out; - if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { req->req_q_in = &ha->mqiobase->isp25mq.req_q_in; req->req_q_out = &ha->mqiobase->isp25mq.req_q_out; rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in; @@ -3395,6 +3341,7 @@ skip_dpc: if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { int prot = 0, guard; + base_vha->flags.difdix_supported = 1; ql_dbg(ql_dbg_init, base_vha, 0x00f1, "Registering for DIF/DIX type 1 and 3 protection.\n"); @@ -3576,7 +3523,8 @@ qla2x00_shutdown(struct pci_dev *pdev) if (ha->eft) qla2x00_disable_eft_trace(vha); - if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) { + if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { if (ha->flags.fw_started) qla2x00_abort_isp_cleanup(vha); } else { @@ -3681,7 +3629,8 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha) if (ha->mqiobase) iounmap(ha->mqiobase); - if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && ha->msixbase) + if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) && + ha->msixbase) iounmap(ha->msixbase); } } @@ -3732,7 +3681,8 @@ qla2x00_remove_one(struct pci_dev *pdev) } qla2x00_wait_for_hba_ready(base_vha); - if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) { + if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { if (ha->flags.fw_started) qla2x00_abort_isp_cleanup(base_vha); } else if (!IS_QLAFX00(ha)) { @@ -3770,8 +3720,6 @@ qla2x00_remove_one(struct pci_dev *pdev) qla2x00_delete_all_vps(ha, base_vha); - qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); - qla2x00_dfs_remove(base_vha); qla84xx_put_chip(base_vha); @@ -3860,11 +3808,8 @@ void qla2x00_free_fcports(struct scsi_qla_host *vha) { fc_port_t *fcport, *tfcport; - list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) { - list_del(&fcport->list); - qla2x00_clear_loop_id(fcport); - kfree(fcport); - } + list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) + qla2x00_free_fcport(fcport); } static inline void @@ -3889,6 +3834,7 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, qla2xxx_wake_dpc(base_vha); } else { int now; + if (rport) { ql_dbg(ql_dbg_disc, fcport->vha, 0x2109, "%s %8phN. rport %p roles %x\n", @@ -3980,6 +3926,19 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) } } +static void qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha) +{ + int i; + + if (IS_FWI2_CAPABLE(ha)) + return; + + for (i = 0; i < SNS_FIRST_LOOP_ID; i++) + set_bit(i, ha->loop_id_map); + set_bit(MANAGEMENT_SERVER, ha->loop_id_map); + set_bit(BROADCAST, ha->loop_id_map); +} + /* * qla2x00_mem_alloc * Allocates adapter memory. @@ -4222,7 +4181,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, ha->npiv_info = NULL; /* Get consistent memory allocated for EX-INIT-CB. */ - if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) { + if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &ha->ex_init_cb_dma); if (!ha->ex_init_cb) @@ -4265,8 +4225,20 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, goto fail_sfp_data; } + ha->flt = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, &ha->flt_dma, + GFP_KERNEL); + if (!ha->flt) { + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b, + "Unable to allocate memory for FLT.\n"); + goto fail_flt_buffer; + } + return 0; +fail_flt_buffer: + dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, + ha->sfp_data, ha->sfp_data_dma); fail_sfp_data: kfree(ha->loop_id_map); fail_loop_id_map: @@ -4602,6 +4574,9 @@ qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha) static void qla2x00_free_fw_dump(struct qla_hw_data *ha) { + struct fwdt *fwdt = ha->fwdt; + uint j; + if (ha->fce) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, ha->fce_dma); @@ -4612,8 +4587,6 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha) if (ha->fw_dump) vfree(ha->fw_dump); - if (ha->fw_dump_template) - vfree(ha->fw_dump_template); ha->fce = NULL; ha->fce_dma = 0; @@ -4624,8 +4597,13 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha) ha->fw_dump_reading = 0; ha->fw_dump = NULL; ha->fw_dump_len = 0; - ha->fw_dump_template = NULL; - ha->fw_dump_template_len = 0; + + for (j = 0; j < 2; j++, fwdt++) { + if (fwdt->template) + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + } } /* @@ -4643,44 +4621,68 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->mctp_dump) dma_free_coherent(&ha->pdev->dev, MCTP_DUMP_SIZE, ha->mctp_dump, ha->mctp_dump_dma); + ha->mctp_dump = NULL; mempool_destroy(ha->srb_mempool); + ha->srb_mempool = NULL; if (ha->dcbx_tlv) dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, ha->dcbx_tlv, ha->dcbx_tlv_dma); + ha->dcbx_tlv = NULL; if (ha->xgmac_data) dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, ha->xgmac_data, ha->xgmac_data_dma); + ha->xgmac_data = NULL; if (ha->sns_cmd) dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); + ha->sns_cmd = NULL; + ha->sns_cmd_dma = 0; if (ha->ct_sns) dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); + ha->ct_sns = NULL; + ha->ct_sns_dma = 0; if (ha->sfp_data) dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data, ha->sfp_data_dma); + ha->sfp_data = NULL; + + if (ha->flt) + dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, + ha->flt, ha->flt_dma); + ha->flt = NULL; + ha->flt_dma = 0; if (ha->ms_iocb) dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); + ha->ms_iocb = NULL; + ha->ms_iocb_dma = 0; if (ha->ex_init_cb) dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); + ha->ex_init_cb = NULL; + ha->ex_init_cb_dma = 0; if (ha->async_pd) dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); + ha->async_pd = NULL; + ha->async_pd_dma = 0; dma_pool_destroy(ha->s_dma_pool); + ha->s_dma_pool = NULL; if (ha->gid_list) dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), ha->gid_list, ha->gid_list_dma); + ha->gid_list = NULL; + ha->gid_list_dma = 0; if (IS_QLA82XX(ha)) { if (!list_empty(&ha->gbl_dsd_list)) { @@ -4698,10 +4700,13 @@ qla2x00_mem_free(struct qla_hw_data *ha) } dma_pool_destroy(ha->dl_dma_pool); + ha->dl_dma_pool = NULL; dma_pool_destroy(ha->fcp_cmnd_dma_pool); + ha->fcp_cmnd_dma_pool = NULL; mempool_destroy(ha->ctx_mempool); + ha->ctx_mempool = NULL; if (ql2xenabledif) { struct dsd_dma *dsd, *nxt; @@ -4728,53 +4733,26 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->dif_bundl_pool) dma_pool_destroy(ha->dif_bundl_pool); + ha->dif_bundl_pool = NULL; qlt_mem_free(ha); if (ha->init_cb) dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); + ha->init_cb = NULL; + ha->init_cb_dma = 0; vfree(ha->optrom_buffer); + ha->optrom_buffer = NULL; kfree(ha->nvram); + ha->nvram = NULL; kfree(ha->npiv_info); + ha->npiv_info = NULL; kfree(ha->swl); + ha->swl = NULL; kfree(ha->loop_id_map); - - ha->srb_mempool = NULL; - ha->ctx_mempool = NULL; - ha->sns_cmd = NULL; - ha->sns_cmd_dma = 0; - ha->ct_sns = NULL; - ha->ct_sns_dma = 0; - ha->ms_iocb = NULL; - ha->ms_iocb_dma = 0; - ha->init_cb = NULL; - ha->init_cb_dma = 0; - ha->ex_init_cb = NULL; - ha->ex_init_cb_dma = 0; - ha->async_pd = NULL; - ha->async_pd_dma = 0; ha->loop_id_map = NULL; - ha->npiv_info = NULL; - ha->optrom_buffer = NULL; - ha->swl = NULL; - ha->nvram = NULL; - ha->mctp_dump = NULL; - ha->dcbx_tlv = NULL; - ha->xgmac_data = NULL; - ha->sfp_data = NULL; - - ha->s_dma_pool = NULL; - ha->dl_dma_pool = NULL; - ha->fcp_cmnd_dma_pool = NULL; - - ha->gid_list = NULL; - ha->gid_list_dma = 0; - - ha->tgt.atio_ring = NULL; - ha->tgt.atio_dma = 0; - ha->tgt.tgt_vp_map = NULL; } struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, @@ -4811,7 +4789,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->plogi_ack_list); INIT_LIST_HEAD(&vha->qp_list); INIT_LIST_HEAD(&vha->gnl.fcports); - INIT_LIST_HEAD(&vha->nvme_rport_list); INIT_LIST_HEAD(&vha->gpnid_list); INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn); @@ -5608,6 +5585,7 @@ qla83xx_force_lock_recovery(scsi_qla_host_t *base_vha) uint32_t idc_lck_rcvry_stage_mask = 0x3; uint32_t idc_lck_rcvry_owner_mask = 0x3c; struct qla_hw_data *ha = base_vha->hw; + ql_dbg(ql_dbg_p3p, base_vha, 0xb086, "Trying force recovery of the IDC lock.\n"); @@ -6677,8 +6655,10 @@ qla2x00_timer(struct timer_list *t) * FC-NVME * see if the active AEN count has changed from what was last reported. */ - if (!vha->vp_idx && (atomic_read(&ha->nvme_active_aen_cnt) != - ha->nvme_last_rptd_aen) && ha->zio_mode == QLA_ZIO_MODE_6) { + if (!vha->vp_idx && + (atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen) && + ha->zio_mode == QLA_ZIO_MODE_6 && + !ha->flags.host_shutting_down) { ql_log(ql_log_info, vha, 0x3002, "nvme: Sched: Set ZIO exchange threshold to %d.\n", ha->nvme_last_rptd_aen); @@ -6690,7 +6670,7 @@ qla2x00_timer(struct timer_list *t) if (!vha->vp_idx && (atomic_read(&ha->zio_threshold) != ha->last_zio_threshold) && (ha->zio_mode == QLA_ZIO_MODE_6) && - (IS_QLA83XX(ha) || IS_QLA27XX(ha))) { + (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) { ql_log(ql_log_info, vha, 0x3002, "Sched: Set ZIO exchange threshold to %d.\n", ha->last_zio_threshold); @@ -6736,7 +6716,6 @@ qla2x00_timer(struct timer_list *t) /* Firmware interface routines. */ -#define FW_BLOBS 11 #define FW_ISP21XX 0 #define FW_ISP22XX 1 #define FW_ISP2300 2 @@ -6748,6 +6727,7 @@ qla2x00_timer(struct timer_list *t) #define FW_ISP2031 8 #define FW_ISP8031 9 #define FW_ISP27XX 10 +#define FW_ISP28XX 11 #define FW_FILE_ISP21XX "ql2100_fw.bin" #define FW_FILE_ISP22XX "ql2200_fw.bin" @@ -6760,11 +6740,12 @@ qla2x00_timer(struct timer_list *t) #define FW_FILE_ISP2031 "ql2600_fw.bin" #define FW_FILE_ISP8031 "ql8300_fw.bin" #define FW_FILE_ISP27XX "ql2700_fw.bin" +#define FW_FILE_ISP28XX "ql2800_fw.bin" static DEFINE_MUTEX(qla_fw_lock); -static struct fw_blob qla_fw_blobs[FW_BLOBS] = { +static struct fw_blob qla_fw_blobs[] = { { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, }, { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, }, { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, }, @@ -6776,6 +6757,8 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = { { .name = FW_FILE_ISP2031, }, { .name = FW_FILE_ISP8031, }, { .name = FW_FILE_ISP27XX, }, + { .name = FW_FILE_ISP28XX, }, + { .name = NULL, }, }; struct fw_blob * @@ -6806,10 +6789,15 @@ qla2x00_request_firmware(scsi_qla_host_t *vha) blob = &qla_fw_blobs[FW_ISP8031]; } else if (IS_QLA27XX(ha)) { blob = &qla_fw_blobs[FW_ISP27XX]; + } else if (IS_QLA28XX(ha)) { + blob = &qla_fw_blobs[FW_ISP28XX]; } else { return NULL; } + if (!blob->name) + return NULL; + mutex_lock(&qla_fw_lock); if (blob->fw) goto out; @@ -6819,7 +6807,6 @@ qla2x00_request_firmware(scsi_qla_host_t *vha) "Failed to load firmware image (%s).\n", blob->name); blob->fw = NULL; blob = NULL; - goto out; } out: @@ -6830,14 +6817,86 @@ out: static void qla2x00_release_firmware(void) { - int idx; + struct fw_blob *blob; mutex_lock(&qla_fw_lock); - for (idx = 0; idx < FW_BLOBS; idx++) - release_firmware(qla_fw_blobs[idx].fw); + for (blob = qla_fw_blobs; blob->name; blob++) + release_firmware(blob->fw); mutex_unlock(&qla_fw_lock); } +static void qla_pci_error_cleanup(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + struct qla_qpair *qpair = NULL; + struct scsi_qla_host *vp; + fc_port_t *fcport; + int i; + unsigned long flags; + + ha->chip_reset++; + + ha->base_qpair->chip_reset = ha->chip_reset; + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) + ha->queue_pair_map[i]->chip_reset = + ha->base_qpair->chip_reset; + } + + /* purge MBox commands */ + if (atomic_read(&ha->num_pend_mbx_stage3)) { + clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + complete(&ha->mbx_intr_comp); + } + + i = 0; + + while (atomic_read(&ha->num_pend_mbx_stage3) || + atomic_read(&ha->num_pend_mbx_stage2) || + atomic_read(&ha->num_pend_mbx_stage1)) { + msleep(20); + i++; + if (i > 50) + break; + } + + ha->flags.purge_mbox = 0; + + mutex_lock(&ha->mq_lock); + list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) + qpair->online = 0; + mutex_unlock(&ha->mq_lock); + + qla2x00_mark_all_devices_lost(vha, 0); + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) { + atomic_inc(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + qla2x00_mark_all_devices_lost(vp, 0); + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vp->vref_count); + } + spin_unlock_irqrestore(&ha->vport_slock, flags); + + /* Clear all async request states across all VPs. */ + list_for_each_entry(fcport, &vha->vp_fcports, list) + fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) { + atomic_inc(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + list_for_each_entry(fcport, &vp->vp_fcports, list) + fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vp->vref_count); + } + spin_unlock_irqrestore(&ha->vport_slock, flags); +} + + static pci_ers_result_t qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { @@ -6863,20 +6922,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: ha->flags.eeh_busy = 1; - /* For ISP82XX complete any pending mailbox cmd */ - if (IS_QLA82XX(ha)) { - ha->flags.isp82xx_fw_hung = 1; - ql_dbg(ql_dbg_aer, vha, 0x9001, "Pci channel io frozen\n"); - qla82xx_clear_pending_mbx(vha); - } - qla2x00_free_irqs(vha); - pci_disable_device(pdev); - /* Return back all IOs */ - qla2x00_abort_all_cmds(vha, DID_RESET << 16); - if (ql2xmqsupport || ql2xnvmeenable) { - set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } + qla_pci_error_cleanup(vha); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: ha->flags.pci_channel_io_perm_failure = 1; @@ -6930,122 +6976,14 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } -static uint32_t -qla82xx_error_recovery(scsi_qla_host_t *base_vha) -{ - uint32_t rval = QLA_FUNCTION_FAILED; - uint32_t drv_active = 0; - struct qla_hw_data *ha = base_vha->hw; - int fn; - struct pci_dev *other_pdev = NULL; - - ql_dbg(ql_dbg_aer, base_vha, 0x9006, - "Entered %s.\n", __func__); - - set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - - if (base_vha->flags.online) { - /* Abort all outstanding commands, - * so as to be requeued later */ - qla2x00_abort_isp_cleanup(base_vha); - } - - - fn = PCI_FUNC(ha->pdev->devfn); - while (fn > 0) { - fn--; - ql_dbg(ql_dbg_aer, base_vha, 0x9007, - "Finding pci device at function = 0x%x.\n", fn); - other_pdev = - pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), - ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), - fn)); - - if (!other_pdev) - continue; - if (atomic_read(&other_pdev->enable_cnt)) { - ql_dbg(ql_dbg_aer, base_vha, 0x9008, - "Found PCI func available and enable at 0x%x.\n", - fn); - pci_dev_put(other_pdev); - break; - } - pci_dev_put(other_pdev); - } - - if (!fn) { - /* Reset owner */ - ql_dbg(ql_dbg_aer, base_vha, 0x9009, - "This devfn is reset owner = 0x%x.\n", - ha->pdev->devfn); - qla82xx_idc_lock(ha); - - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA8XXX_DEV_INITIALIZING); - - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, - QLA82XX_IDC_VERSION); - - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - ql_dbg(ql_dbg_aer, base_vha, 0x900a, - "drv_active = 0x%x.\n", drv_active); - - qla82xx_idc_unlock(ha); - /* Reset if device is not already reset - * drv_active would be 0 if a reset has already been done - */ - if (drv_active) - rval = qla82xx_start_firmware(base_vha); - else - rval = QLA_SUCCESS; - qla82xx_idc_lock(ha); - - if (rval != QLA_SUCCESS) { - ql_log(ql_log_info, base_vha, 0x900b, - "HW State: FAILED.\n"); - qla82xx_clear_drv_active(ha); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA8XXX_DEV_FAILED); - } else { - ql_log(ql_log_info, base_vha, 0x900c, - "HW State: READY.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA8XXX_DEV_READY); - qla82xx_idc_unlock(ha); - ha->flags.isp82xx_fw_hung = 0; - rval = qla82xx_restart_isp(base_vha); - qla82xx_idc_lock(ha); - /* Clear driver state register */ - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); - qla82xx_set_drv_active(base_vha); - } - qla82xx_idc_unlock(ha); - } else { - ql_dbg(ql_dbg_aer, base_vha, 0x900d, - "This devfn is not reset owner = 0x%x.\n", - ha->pdev->devfn); - if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == - QLA8XXX_DEV_READY)) { - ha->flags.isp82xx_fw_hung = 0; - rval = qla82xx_restart_isp(base_vha); - qla82xx_idc_lock(ha); - qla82xx_set_drv_active(base_vha); - qla82xx_idc_unlock(ha); - } - } - clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - - return rval; -} - static pci_ers_result_t qla2xxx_pci_slot_reset(struct pci_dev *pdev) { pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); struct qla_hw_data *ha = base_vha->hw; - struct rsp_que *rsp; - int rc, retries = 10; + int rc; + struct qla_qpair *qpair = NULL; ql_dbg(ql_dbg_aer, base_vha, 0x9004, "Slot Reset.\n"); @@ -7074,24 +7012,16 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) goto exit_slot_reset; } - rsp = ha->rsp_q_map[0]; - if (qla2x00_request_irqs(ha, rsp)) - goto exit_slot_reset; if (ha->isp_ops->pci_config(base_vha)) goto exit_slot_reset; - if (IS_QLA82XX(ha)) { - if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) { - ret = PCI_ERS_RESULT_RECOVERED; - goto exit_slot_reset; - } else - goto exit_slot_reset; - } - - while (ha->flags.mbox_busy && retries--) - msleep(1000); + mutex_lock(&ha->mq_lock); + list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) + qpair->online = 1; + mutex_unlock(&ha->mq_lock); + base_vha->flags.online = 1; set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS) ret = PCI_ERS_RESULT_RECOVERED; @@ -7115,13 +7045,13 @@ qla2xxx_pci_resume(struct pci_dev *pdev) ql_dbg(ql_dbg_aer, base_vha, 0x900f, "pci_resume.\n"); + ha->flags.eeh_busy = 0; + ret = qla2x00_wait_for_hba_online(base_vha); if (ret != QLA_SUCCESS) { ql_log(ql_log_fatal, base_vha, 0x9002, "The device failed to resume I/O from slot/link_reset.\n"); } - - ha->flags.eeh_busy = 0; } static void @@ -7179,7 +7109,7 @@ static int qla2xxx_map_queues(struct Scsi_Host *shost) { int rc; scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata; - struct blk_mq_queue_map *qmap = &shost->tag_set.map[0]; + struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; if (USER_CTRL_IRQ(vha->hw) || !vha->hw->mqiobase) rc = blk_mq_map_queues(qmap); @@ -7188,6 +7118,37 @@ static int qla2xxx_map_queues(struct Scsi_Host *shost) return rc; } +struct scsi_host_template qla2xxx_driver_template = { + .module = THIS_MODULE, + .name = QLA2XXX_DRIVER_NAME, + .queuecommand = qla2xxx_queuecommand, + + .eh_timed_out = fc_eh_timed_out, + .eh_abort_handler = qla2xxx_eh_abort, + .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_target_reset_handler = qla2xxx_eh_target_reset, + .eh_bus_reset_handler = qla2xxx_eh_bus_reset, + .eh_host_reset_handler = qla2xxx_eh_host_reset, + + .slave_configure = qla2xxx_slave_configure, + + .slave_alloc = qla2xxx_slave_alloc, + .slave_destroy = qla2xxx_slave_destroy, + .scan_finished = qla2xxx_scan_finished, + .scan_start = qla2xxx_scan_start, + .change_queue_depth = scsi_change_queue_depth, + .map_queues = qla2xxx_map_queues, + .this_id = -1, + .cmd_per_lun = 3, + .sg_tablesize = SG_ALL, + + .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, + + .supported_mode = MODE_INITIATOR, + .track_queue_depth = 1, +}; + static const struct pci_error_handlers qla2xxx_err_handler = { .error_detected = qla2xxx_pci_error_detected, .mmio_enabled = qla2xxx_pci_mmio_enabled, @@ -7220,6 +7181,11 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2071) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2271) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2261) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2061) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2081) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2281) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2089) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2289) }, { 0 }, }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); @@ -7249,6 +7215,30 @@ qla2x00_module_init(void) { int ret = 0; + BUILD_BUG_ON(sizeof(cmd_entry_t) != 64); + BUILD_BUG_ON(sizeof(cont_a64_entry_t) != 64); + BUILD_BUG_ON(sizeof(cont_entry_t) != 64); + BUILD_BUG_ON(sizeof(init_cb_t) != 96); + BUILD_BUG_ON(sizeof(ms_iocb_entry_t) != 64); + BUILD_BUG_ON(sizeof(request_t) != 64); + BUILD_BUG_ON(sizeof(struct access_chip_84xx) != 64); + BUILD_BUG_ON(sizeof(struct cmd_bidir) != 64); + BUILD_BUG_ON(sizeof(struct cmd_nvme) != 64); + BUILD_BUG_ON(sizeof(struct cmd_type_6) != 64); + BUILD_BUG_ON(sizeof(struct cmd_type_7) != 64); + BUILD_BUG_ON(sizeof(struct cmd_type_7_fx00) != 64); + BUILD_BUG_ON(sizeof(struct cmd_type_crc_2) != 64); + BUILD_BUG_ON(sizeof(struct ct_entry_24xx) != 64); + BUILD_BUG_ON(sizeof(struct ctio_crc2_to_fw) != 64); + BUILD_BUG_ON(sizeof(struct els_entry_24xx) != 64); + BUILD_BUG_ON(sizeof(struct fxdisc_entry_fx00) != 64); + BUILD_BUG_ON(sizeof(struct init_cb_24xx) != 128); + BUILD_BUG_ON(sizeof(struct init_cb_81xx) != 128); + BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64); + BUILD_BUG_ON(sizeof(struct sns_cmd_pkt) != 2064); + BUILD_BUG_ON(sizeof(struct verify_chip_entry_84xx) != 64); + BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56); + /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, SLAB_HWCACHE_ALIGN, NULL); @@ -7261,8 +7251,7 @@ qla2x00_module_init(void) /* Initialize target kmem_cache and mem_pools */ ret = qlt_init(); if (ret < 0) { - kmem_cache_destroy(srb_cachep); - return ret; + goto destroy_cache; } else if (ret > 0) { /* * If initiator mode is explictly disabled by qlt_init(), @@ -7286,11 +7275,10 @@ qla2x00_module_init(void) qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) { - kmem_cache_destroy(srb_cachep); ql_log(ql_log_fatal, NULL, 0x0002, "fc_attach_transport failed...Failing load!.\n"); - qlt_exit(); - return -ENODEV; + ret = -ENODEV; + goto qlt_exit; } apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops); @@ -7302,27 +7290,37 @@ qla2x00_module_init(void) qla2xxx_transport_vport_template = fc_attach_transport(&qla2xxx_transport_vport_functions); if (!qla2xxx_transport_vport_template) { - kmem_cache_destroy(srb_cachep); - qlt_exit(); - fc_release_transport(qla2xxx_transport_template); ql_log(ql_log_fatal, NULL, 0x0004, "fc_attach_transport vport failed...Failing load!.\n"); - return -ENODEV; + ret = -ENODEV; + goto unreg_chrdev; } ql_log(ql_log_info, NULL, 0x0005, "QLogic Fibre Channel HBA Driver: %s.\n", qla2x00_version_str); ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { - kmem_cache_destroy(srb_cachep); - qlt_exit(); - fc_release_transport(qla2xxx_transport_template); - fc_release_transport(qla2xxx_transport_vport_template); ql_log(ql_log_fatal, NULL, 0x0006, "pci_register_driver failed...ret=%d Failing load!.\n", ret); + goto release_vport_transport; } return ret; + +release_vport_transport: + fc_release_transport(qla2xxx_transport_vport_template); + +unreg_chrdev: + if (apidev_major >= 0) + unregister_chrdev(apidev_major, QLA2XXX_APIDEV); + fc_release_transport(qla2xxx_transport_template); + +qlt_exit: + qlt_exit(); + +destroy_cache: + kmem_cache_destroy(srb_cachep); + return ret; } /** @@ -7331,14 +7329,15 @@ qla2x00_module_init(void) static void __exit qla2x00_module_exit(void) { - unregister_chrdev(apidev_major, QLA2XXX_APIDEV); pci_unregister_driver(&qla2xxx_pci_driver); qla2x00_release_firmware(); - kmem_cache_destroy(srb_cachep); - qlt_exit(); kmem_cache_destroy(ctx_cachep); - fc_release_transport(qla2xxx_transport_template); fc_release_transport(qla2xxx_transport_vport_template); + if (apidev_major >= 0) + unregister_chrdev(apidev_major, QLA2XXX_APIDEV); + fc_release_transport(qla2xxx_transport_template); + qlt_exit(); + kmem_cache_destroy(srb_cachep); } module_init(qla2x00_module_init); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 2a3055c799fb..1eb82384d933 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -429,66 +429,64 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat) static inline uint32_t flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr) { - return ha->flash_conf_off | faddr; + return ha->flash_conf_off + faddr; } static inline uint32_t flash_data_addr(struct qla_hw_data *ha, uint32_t faddr) { - return ha->flash_data_off | faddr; + return ha->flash_data_off + faddr; } static inline uint32_t nvram_conf_addr(struct qla_hw_data *ha, uint32_t naddr) { - return ha->nvram_conf_off | naddr; + return ha->nvram_conf_off + naddr; } static inline uint32_t nvram_data_addr(struct qla_hw_data *ha, uint32_t naddr) { - return ha->nvram_data_off | naddr; + return ha->nvram_data_off + naddr; } -static uint32_t -qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr) +static int +qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t *data) { - int rval; - uint32_t cnt, data; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + ulong cnt = 30000; WRT_REG_DWORD(®->flash_addr, addr & ~FARX_DATA_FLAG); - /* Wait for READ cycle to complete. */ - rval = QLA_SUCCESS; - for (cnt = 3000; - (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(10); - else - rval = QLA_FUNCTION_TIMEOUT; + + while (cnt--) { + if (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) { + *data = RD_REG_DWORD(®->flash_data); + return QLA_SUCCESS; + } + udelay(10); cond_resched(); } - /* TODO: What happens if we time out? */ - data = 0xDEADDEAD; - if (rval == QLA_SUCCESS) - data = RD_REG_DWORD(®->flash_data); - - return data; + ql_log(ql_log_warn, pci_get_drvdata(ha->pdev), 0x7090, + "Flash read dword at %x timeout.\n", addr); + *data = 0xDEADDEAD; + return QLA_FUNCTION_TIMEOUT; } uint32_t * qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { - uint32_t i; + ulong i; struct qla_hw_data *ha = vha->hw; /* Dword reads to flash. */ - for (i = 0; i < dwords; i++, faddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - flash_data_addr(ha, faddr))); + faddr = flash_data_addr(ha, faddr); + for (i = 0; i < dwords; i++, faddr++, dwptr++) { + if (qla24xx_read_flash_dword(ha, faddr, dwptr)) + break; + cpu_to_le32s(dwptr); + } return dwptr; } @@ -496,35 +494,37 @@ qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, static int qla24xx_write_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t data) { - int rval; - uint32_t cnt; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + ulong cnt = 500000; WRT_REG_DWORD(®->flash_data, data); - RD_REG_DWORD(®->flash_data); /* PCI Posting. */ WRT_REG_DWORD(®->flash_addr, addr | FARX_DATA_FLAG); - /* Wait for Write cycle to complete. */ - rval = QLA_SUCCESS; - for (cnt = 500000; (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(10); - else - rval = QLA_FUNCTION_TIMEOUT; + + while (cnt--) { + if (!(RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG)) + return QLA_SUCCESS; + udelay(10); cond_resched(); } - return rval; + + ql_log(ql_log_warn, pci_get_drvdata(ha->pdev), 0x7090, + "Flash write dword at %x timeout.\n", addr); + return QLA_FUNCTION_TIMEOUT; } static void qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id, uint8_t *flash_id) { - uint32_t ids; + uint32_t faddr, ids = 0; - ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x03ab)); - *man_id = LSB(ids); - *flash_id = MSB(ids); + *man_id = *flash_id = 0; + + faddr = flash_conf_addr(ha, 0x03ab); + if (!qla24xx_read_flash_dword(ha, faddr, &ids)) { + *man_id = LSB(ids); + *flash_id = MSB(ids); + } /* Check if man_id and flash_id are valid. */ if (ids != 0xDEADDEAD && (*man_id == 0 || *flash_id == 0)) { @@ -534,9 +534,11 @@ qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id, * Example: ATMEL 0x00 01 45 1F * Extract MFG and Dev ID from last two bytes. */ - ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x009f)); - *man_id = LSB(ids); - *flash_id = MSB(ids); + faddr = flash_conf_addr(ha, 0x009f); + if (!qla24xx_read_flash_dword(ha, faddr, &ids)) { + *man_id = LSB(ids); + *flash_id = MSB(ids); + } } } @@ -545,12 +547,12 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) { const char *loc, *locations[] = { "DEF", "PCI" }; uint32_t pcihdr, pcids; - uint32_t *dcode; - uint8_t *buf, *bcode, last_image; uint16_t cnt, chksum, *wptr; - struct qla_flt_location *fltl; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + struct qla_flt_location *fltl = (void *)req->ring; + uint32_t *dcode = (void *)req->ring; + uint8_t *buf = (void *)req->ring, *bcode, last_image; /* * FLT-location structure resides after the last PCI region. @@ -571,12 +573,13 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { *start = FA_FLASH_LAYOUT_ADDR_83; goto end; + } else if (IS_QLA28XX(ha)) { + *start = FA_FLASH_LAYOUT_ADDR_28; + goto end; } + /* Begin with first PCI expansion ROM header. */ - buf = (uint8_t *)req->ring; - dcode = (uint32_t *)req->ring; pcihdr = 0; - last_image = 1; do { /* Verify PCI expansion ROM header. */ qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20); @@ -601,22 +604,19 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) } while (!last_image); /* Now verify FLT-location structure. */ - fltl = (struct qla_flt_location *)req->ring; - qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, - sizeof(struct qla_flt_location) >> 2); - if (fltl->sig[0] != 'Q' || fltl->sig[1] != 'F' || - fltl->sig[2] != 'L' || fltl->sig[3] != 'T') + qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, sizeof(*fltl) >> 2); + if (memcmp(fltl->sig, "QFLT", 4)) goto end; - wptr = (uint16_t *)req->ring; - cnt = sizeof(struct qla_flt_location) >> 1; + wptr = (void *)req->ring; + cnt = sizeof(*fltl) / sizeof(*wptr); for (chksum = 0; cnt--; wptr++) chksum += le16_to_cpu(*wptr); if (chksum) { ql_log(ql_log_fatal, vha, 0x0045, "Inconsistent FLTL detected: checksum=0x%x.\n", chksum); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010e, - buf, sizeof(struct qla_flt_location)); + fltl, sizeof(*fltl)); return QLA_FUNCTION_FAILED; } @@ -634,7 +634,7 @@ end: static void qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) { - const char *loc, *locations[] = { "DEF", "FLT" }; + const char *locations[] = { "DEF", "FLT" }, *loc = locations[1]; const uint32_t def_fw[] = { FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 }; const uint32_t def_boot[] = @@ -664,20 +664,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) const uint32_t fcp_prio_cfg1[] = { FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25, 0 }; - uint32_t def; - uint16_t *wptr; - uint16_t cnt, chksum; - uint32_t start; - struct qla_flt_header *flt; - struct qla_flt_region *region; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - def = 0; - if (IS_QLA25XX(ha)) - def = 1; - else if (IS_QLA81XX(ha)) - def = 2; + struct qla_hw_data *ha = vha->hw; + uint32_t def = IS_QLA81XX(ha) ? 2 : IS_QLA25XX(ha) ? 1 : 0; + struct qla_flt_header *flt = (void *)ha->flt; + struct qla_flt_region *region = (void *)&flt[1]; + uint16_t *wptr, cnt, chksum; + uint32_t start; /* Assign FCP prio region since older adapters may not have FLT, or FCP prio region in it's FLT. @@ -686,12 +679,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) fcp_prio_cfg0[def] : fcp_prio_cfg1[def]; ha->flt_region_flt = flt_addr; - wptr = (uint16_t *)req->ring; - flt = (struct qla_flt_header *)req->ring; - region = (struct qla_flt_region *)&flt[1]; - ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, - flt_addr << 2, OPTROM_BURST_SIZE); - if (*wptr == cpu_to_le16(0xffff)) + wptr = (uint16_t *)ha->flt; + qla24xx_read_flash_data(vha, (void *)flt, flt_addr, + (sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE) >> 2); + + if (le16_to_cpu(*wptr) == 0xffff) goto no_flash_data; if (flt->version != cpu_to_le16(1)) { ql_log(ql_log_warn, vha, 0x0047, @@ -701,7 +693,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) goto no_flash_data; } - cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1; + cnt = (sizeof(*flt) + le16_to_cpu(flt->length)) / sizeof(*wptr); for (chksum = 0; cnt--; wptr++) chksum += le16_to_cpu(*wptr); if (chksum) { @@ -712,18 +704,20 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) goto no_flash_data; } - loc = locations[1]; - cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); + cnt = le16_to_cpu(flt->length) / sizeof(*region); for ( ; cnt; cnt--, region++) { /* Store addresses as DWORD offsets. */ start = le32_to_cpu(region->start) >> 2; ql_dbg(ql_dbg_init, vha, 0x0049, - "FLT[%02x]: start=0x%x " - "end=0x%x size=0x%x.\n", le32_to_cpu(region->code) & 0xff, - start, le32_to_cpu(region->end) >> 2, - le32_to_cpu(region->size)); - - switch (le32_to_cpu(region->code) & 0xff) { + "FLT[%#x]: start=%#x end=%#x size=%#x.\n", + le16_to_cpu(region->code), start, + le32_to_cpu(region->end) >> 2, + le32_to_cpu(region->size) >> 2); + if (region->attribute) + ql_log(ql_dbg_init, vha, 0xffff, + "Region %x is secure\n", region->code); + + switch (le16_to_cpu(region->code)) { case FLT_REG_FCOE_FW: if (!IS_QLA8031(ha)) break; @@ -753,13 +747,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) ha->flt_region_vpd = start; break; case FLT_REG_VPD_2: - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) break; if (ha->port_no == 2) ha->flt_region_vpd = start; break; case FLT_REG_VPD_3: - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) break; if (ha->port_no == 3) ha->flt_region_vpd = start; @@ -777,13 +771,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) ha->flt_region_nvram = start; break; case FLT_REG_NVRAM_2: - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) break; if (ha->port_no == 2) ha->flt_region_nvram = start; break; case FLT_REG_NVRAM_3: - if (!IS_QLA27XX(ha)) + if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) break; if (ha->port_no == 3) ha->flt_region_nvram = start; @@ -847,36 +841,74 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) ha->flt_region_nvram = start; break; case FLT_REG_IMG_PRI_27XX: - if (IS_QLA27XX(ha)) + if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) ha->flt_region_img_status_pri = start; break; case FLT_REG_IMG_SEC_27XX: - if (IS_QLA27XX(ha)) + if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) ha->flt_region_img_status_sec = start; break; case FLT_REG_FW_SEC_27XX: - if (IS_QLA27XX(ha)) + if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) ha->flt_region_fw_sec = start; break; case FLT_REG_BOOTLOAD_SEC_27XX: - if (IS_QLA27XX(ha)) + if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) ha->flt_region_boot_sec = start; break; + case FLT_REG_AUX_IMG_PRI_28XX: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + ha->flt_region_aux_img_status_pri = start; + break; + case FLT_REG_AUX_IMG_SEC_28XX: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + ha->flt_region_aux_img_status_sec = start; + break; + case FLT_REG_NVRAM_SEC_28XX_0: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 0) + ha->flt_region_nvram_sec = start; + break; + case FLT_REG_NVRAM_SEC_28XX_1: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 1) + ha->flt_region_nvram_sec = start; + break; + case FLT_REG_NVRAM_SEC_28XX_2: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 2) + ha->flt_region_nvram_sec = start; + break; + case FLT_REG_NVRAM_SEC_28XX_3: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 3) + ha->flt_region_nvram_sec = start; + break; case FLT_REG_VPD_SEC_27XX_0: - if (IS_QLA27XX(ha)) - ha->flt_region_vpd_sec = start; + case FLT_REG_VPD_SEC_28XX_0: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + ha->flt_region_vpd_nvram_sec = start; + if (ha->port_no == 0) + ha->flt_region_vpd_sec = start; + } break; case FLT_REG_VPD_SEC_27XX_1: - if (IS_QLA27XX(ha)) - ha->flt_region_vpd_sec = start; + case FLT_REG_VPD_SEC_28XX_1: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 1) + ha->flt_region_vpd_sec = start; break; case FLT_REG_VPD_SEC_27XX_2: - if (IS_QLA27XX(ha)) - ha->flt_region_vpd_sec = start; + case FLT_REG_VPD_SEC_28XX_2: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 2) + ha->flt_region_vpd_sec = start; break; case FLT_REG_VPD_SEC_27XX_3: - if (IS_QLA27XX(ha)) - ha->flt_region_vpd_sec = start; + case FLT_REG_VPD_SEC_28XX_3: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (ha->port_no == 3) + ha->flt_region_vpd_sec = start; break; } } @@ -912,22 +944,19 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) #define FLASH_BLK_SIZE_32K 0x8000 #define FLASH_BLK_SIZE_64K 0x10000 const char *loc, *locations[] = { "MID", "FDT" }; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; uint16_t cnt, chksum; - uint16_t *wptr; - struct qla_fdt_layout *fdt; + uint16_t *wptr = (void *)req->ring; + struct qla_fdt_layout *fdt = (void *)req->ring; uint8_t man_id, flash_id; uint16_t mid = 0, fid = 0; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - wptr = (uint16_t *)req->ring; - fdt = (struct qla_fdt_layout *)req->ring; - ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, - ha->flt_region_fdt << 2, OPTROM_BURST_SIZE); - if (*wptr == cpu_to_le16(0xffff)) + qla24xx_read_flash_data(vha, (void *)fdt, ha->flt_region_fdt, + OPTROM_BURST_DWORDS); + if (le16_to_cpu(*wptr) == 0xffff) goto no_flash_data; - if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || - fdt->sig[3] != 'D') + if (memcmp(fdt->sig, "QLID", 4)) goto no_flash_data; for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++) @@ -938,7 +967,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) " checksum=0x%x id=%c version0x%x.\n", chksum, fdt->sig[0], le16_to_cpu(fdt->version)); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113, - (uint8_t *)fdt, sizeof(*fdt)); + fdt, sizeof(*fdt)); goto no_flash_data; } @@ -958,7 +987,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 | fdt->unprotect_sec_cmd); ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? - flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd): + flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd) : flash_conf_addr(ha, 0x0336); } goto done; @@ -1019,8 +1048,7 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha) return; wptr = (uint32_t *)req->ring; - ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, - QLA82XX_IDC_PARAM_ADDR , 8); + ha->isp_ops->read_optrom(vha, req->ring, QLA82XX_IDC_PARAM_ADDR, 8); if (*wptr == cpu_to_le32(0xffffffff)) { ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT; @@ -1045,7 +1073,8 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && - !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha)) + !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return QLA_SUCCESS; ret = qla2xxx_find_flt_start(vha, &flt_addr); @@ -1081,8 +1110,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) if (IS_QLA8044(ha)) return; - ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr, - ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header)); + ha->isp_ops->read_optrom(vha, &hdr, ha->flt_region_npiv_conf << 2, + sizeof(struct qla_npiv_header)); if (hdr.version == cpu_to_le16(0xffff)) return; if (hdr.version != cpu_to_le16(1)) { @@ -1101,8 +1130,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) return; } - ha->isp_ops->read_optrom(vha, (uint8_t *)data, - ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE); + ha->isp_ops->read_optrom(vha, data, ha->flt_region_npiv_conf << 2, + NPIV_CONFIG_SIZE); cnt = (sizeof(hdr) + le16_to_cpu(hdr.entries) * sizeof(*entry)) >> 1; for (wptr = data, chksum = 0; cnt--; wptr++) @@ -1139,10 +1168,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) vid.node_name = wwn_to_u64(entry->node_name); ql_dbg(ql_dbg_user, vha, 0x7093, - "NPIV[%02x]: wwpn=%llx " - "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt, - (unsigned long long)vid.port_name, - (unsigned long long)vid.node_name, + "NPIV[%02x]: wwpn=%llx wwnn=%llx vf_id=%#x Q_qos=%#x F_qos=%#x.\n", + cnt, vid.port_name, vid.node_name, le16_to_cpu(entry->vf_id), entry->q_qos, entry->f_qos); @@ -1150,10 +1177,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) vport = fc_vport_create(vha->host, 0, &vid); if (!vport) ql_log(ql_log_warn, vha, 0x7094, - "NPIV-Config Failed to create vport [%02x]: " - "wwpn=%llx wwnn=%llx.\n", cnt, - (unsigned long long)vid.port_name, - (unsigned long long)vid.node_name); + "NPIV-Config Failed to create vport [%02x]: wwpn=%llx wwnn=%llx.\n", + cnt, vid.port_name, vid.node_name); } } done: @@ -1188,9 +1213,10 @@ done: static int qla24xx_protect_flash(scsi_qla_host_t *vha) { - uint32_t cnt; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + ulong cnt = 300; + uint32_t faddr, dword; if (ha->flags.fac_supported) return qla81xx_fac_do_write_enable(vha, 0); @@ -1199,11 +1225,14 @@ qla24xx_protect_flash(scsi_qla_host_t *vha) goto skip_wrt_protect; /* Enable flash write-protection and wait for completion. */ - qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), - ha->fdt_wrt_disable); - for (cnt = 300; cnt && - qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x005)) & BIT_0; - cnt--) { + faddr = flash_conf_addr(ha, 0x101); + qla24xx_write_flash_dword(ha, faddr, ha->fdt_wrt_disable); + faddr = flash_conf_addr(ha, 0x5); + while (cnt--) { + if (!qla24xx_read_flash_dword(ha, faddr, &dword)) { + if (!(dword & BIT_0)) + break; + } udelay(10); } @@ -1211,7 +1240,6 @@ skip_wrt_protect: /* Disable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ return QLA_SUCCESS; } @@ -1239,107 +1267,103 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { int ret; - uint32_t liter; - uint32_t sec_mask, rest_addr; - uint32_t fdata; + ulong liter; + ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */ + uint32_t sec_mask, rest_addr, fdata; dma_addr_t optrom_dma; void *optrom = NULL; struct qla_hw_data *ha = vha->hw; - /* Prepare burst-capable write on supported ISPs. */ - if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || - IS_QLA27XX(ha)) && - !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) { - optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - &optrom_dma, GFP_KERNEL); - if (!optrom) { - ql_log(ql_log_warn, vha, 0x7095, - "Unable to allocate " - "memory for optrom burst write (%x KB).\n", - OPTROM_BURST_SIZE / 1024); - } - } + if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + goto next; - rest_addr = (ha->fdt_block_size >> 2) - 1; - sec_mask = ~rest_addr; + /* Allocate dma buffer for burst write */ + optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + &optrom_dma, GFP_KERNEL); + if (!optrom) { + ql_log(ql_log_warn, vha, 0x7095, + "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE); + } +next: + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Unprotect flash...\n"); ret = qla24xx_unprotect_flash(vha); - if (ret != QLA_SUCCESS) { + if (ret) { ql_log(ql_log_warn, vha, 0x7096, - "Unable to unprotect flash for update.\n"); + "Failed to unprotect flash.\n"); goto done; } + rest_addr = (ha->fdt_block_size >> 2) - 1; + sec_mask = ~rest_addr; for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { fdata = (faddr & sec_mask) << 2; /* Are we at the beginning of a sector? */ - if ((faddr & rest_addr) == 0) { - /* Do sector unprotect. */ - if (ha->fdt_unprotect_sec_cmd) - qla24xx_write_flash_dword(ha, - ha->fdt_unprotect_sec_cmd, - (fdata & 0xff00) | ((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); + if (!(faddr & rest_addr)) { + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Erase sector %#x...\n", faddr); + ret = qla24xx_erase_sector(vha, fdata); - if (ret != QLA_SUCCESS) { + if (ret) { ql_dbg(ql_dbg_user, vha, 0x7007, - "Unable to erase erase sector: address=%x.\n", - faddr); + "Failed to erase sector %x.\n", faddr); break; } } - /* Go with burst-write. */ - if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) { - /* Copy data to DMA'ble buffer. */ - memcpy(optrom, dwptr, OPTROM_BURST_SIZE); + if (optrom) { + /* If smaller than a burst remaining */ + if (dwords - liter < dburst) + dburst = dwords - liter; + /* Copy to dma buffer */ + memcpy(optrom, dwptr, dburst << 2); + + /* Burst write */ + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Write burst (%#lx dwords)...\n", dburst); ret = qla2x00_load_ram(vha, optrom_dma, - flash_data_addr(ha, faddr), - OPTROM_BURST_DWORDS); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7097, - "Unable to burst-write optrom segment " - "(%x/%x/%llx).\n", ret, - flash_data_addr(ha, faddr), - (unsigned long long)optrom_dma); - ql_log(ql_log_warn, vha, 0x7098, - "Reverting to slow-write.\n"); - - dma_free_coherent(&ha->pdev->dev, - OPTROM_BURST_SIZE, optrom, optrom_dma); - optrom = NULL; - } else { - liter += OPTROM_BURST_DWORDS - 1; - faddr += OPTROM_BURST_DWORDS - 1; - dwptr += OPTROM_BURST_DWORDS - 1; + flash_data_addr(ha, faddr), dburst); + if (!ret) { + liter += dburst - 1; + faddr += dburst - 1; + dwptr += dburst - 1; continue; } + + ql_log(ql_log_warn, vha, 0x7097, + "Failed burst-write at %x (%p/%#llx)....\n", + flash_data_addr(ha, faddr), optrom, + (u64)optrom_dma); + + dma_free_coherent(&ha->pdev->dev, + OPTROM_BURST_SIZE, optrom, optrom_dma); + optrom = NULL; + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + break; + ql_log(ql_log_warn, vha, 0x7098, + "Reverting to slow write...\n"); } + /* Slow write */ ret = qla24xx_write_flash_dword(ha, flash_data_addr(ha, faddr), cpu_to_le32(*dwptr)); - if (ret != QLA_SUCCESS) { + if (ret) { ql_dbg(ql_dbg_user, vha, 0x7006, - "Unable to program flash address=%x data=%x.\n", - faddr, *dwptr); + "Failed slopw write %x (%x)\n", faddr, *dwptr); break; } - - /* Do sector protect. */ - if (ha->fdt_unprotect_sec_cmd && - ((faddr & rest_addr) == rest_addr)) - qla24xx_write_flash_dword(ha, - ha->fdt_protect_sec_cmd, - (fdata & 0xff00) | ((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); } + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Protect flash...\n"); ret = qla24xx_protect_flash(vha); - if (ret != QLA_SUCCESS) + if (ret) ql_log(ql_log_warn, vha, 0x7099, - "Unable to protect flash after update.\n"); + "Failed to protect flash\n"); done: if (optrom) dma_free_coherent(&ha->pdev->dev, @@ -1349,7 +1373,7 @@ done: } uint8_t * -qla2x00_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, +qla2x00_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr, uint32_t bytes) { uint32_t i; @@ -1368,27 +1392,30 @@ qla2x00_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, } uint8_t * -qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, +qla24xx_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr, uint32_t bytes) { - uint32_t i; - uint32_t *dwptr; struct qla_hw_data *ha = vha->hw; + uint32_t *dwptr = buf; + uint32_t i; if (IS_P3P_TYPE(ha)) return buf; /* Dword reads to flash. */ - dwptr = (uint32_t *)buf; - for (i = 0; i < bytes >> 2; i++, naddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - nvram_data_addr(ha, naddr))); + naddr = nvram_data_addr(ha, naddr); + bytes >>= 2; + for (i = 0; i < bytes; i++, naddr++, dwptr++) { + if (qla24xx_read_flash_dword(ha, naddr, dwptr)) + break; + cpu_to_le32s(dwptr); + } return buf; } int -qla2x00_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, +qla2x00_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr, uint32_t bytes) { int ret, stat; @@ -1422,14 +1449,14 @@ qla2x00_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, } int -qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, +qla24xx_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr, uint32_t bytes) { - int ret; - uint32_t i; - uint32_t *dwptr; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + uint32_t *dwptr = buf; + uint32_t i; + int ret; ret = QLA_SUCCESS; @@ -1446,11 +1473,10 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0); /* Dword writes to flash. */ - dwptr = (uint32_t *)buf; - for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) { - ret = qla24xx_write_flash_dword(ha, - nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr)); - if (ret != QLA_SUCCESS) { + naddr = nvram_data_addr(ha, naddr); + bytes >>= 2; + for (i = 0; i < bytes; i++, naddr++, dwptr++) { + if (qla24xx_write_flash_dword(ha, naddr, cpu_to_le32(*dwptr))) { ql_dbg(ql_dbg_user, vha, 0x709a, "Unable to program nvram address=%x data=%x.\n", naddr, *dwptr); @@ -1470,31 +1496,34 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, } uint8_t * -qla25xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, +qla25xx_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr, uint32_t bytes) { - uint32_t i; - uint32_t *dwptr; struct qla_hw_data *ha = vha->hw; + uint32_t *dwptr = buf; + uint32_t i; /* Dword reads to flash. */ - dwptr = (uint32_t *)buf; - for (i = 0; i < bytes >> 2; i++, naddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr))); + naddr = flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr); + bytes >>= 2; + for (i = 0; i < bytes; i++, naddr++, dwptr++) { + if (qla24xx_read_flash_dword(ha, naddr, dwptr)) + break; + + cpu_to_le32s(dwptr); + } return buf; } +#define RMW_BUFFER_SIZE (64 * 1024) int -qla25xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, +qla25xx_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr, uint32_t bytes) { struct qla_hw_data *ha = vha->hw; -#define RMW_BUFFER_SIZE (64 * 1024) - uint8_t *dbuf; + uint8_t *dbuf = vmalloc(RMW_BUFFER_SIZE); - dbuf = vmalloc(RMW_BUFFER_SIZE); if (!dbuf) return QLA_MEMORY_ALLOC_FAILED; ha->isp_ops->read_optrom(vha, dbuf, ha->flt_region_vpd_nvram << 2, @@ -1728,7 +1757,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha) { uint32_t led_select_value = 0; - if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) goto out; if (ha->port_no == 0) @@ -1749,13 +1778,14 @@ qla83xx_beacon_blink(struct scsi_qla_host *vha) uint16_t orig_led_cfg[6]; uint32_t led_10_value, led_43_value; - if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha) && !IS_QLA27XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha) && !IS_QLA27XX(ha) && + !IS_QLA28XX(ha)) return; if (!ha->beacon_blink_led) return; - if (IS_QLA27XX(ha)) { + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { qla2x00_write_ram_word(vha, 0x1003, 0x40000230); qla2x00_write_ram_word(vha, 0x1004, 0x40000230); } else if (IS_QLA2031(ha)) { @@ -1845,7 +1875,7 @@ qla24xx_beacon_on(struct scsi_qla_host *vha) return QLA_FUNCTION_FAILED; } - if (IS_QLA2031(ha) || IS_QLA27XX(ha)) + if (IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) goto skip_gpio; spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1885,7 +1915,7 @@ qla24xx_beacon_off(struct scsi_qla_host *vha) ha->beacon_blink_led = 0; - if (IS_QLA2031(ha) || IS_QLA27XX(ha)) + if (IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) goto set_fw_options; if (IS_QLA8031(ha) || IS_QLA81XX(ha)) @@ -2314,8 +2344,8 @@ qla2x00_resume_hba(struct scsi_qla_host *vha) scsi_unblock_requests(vha->host); } -uint8_t * -qla2x00_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +void * +qla2x00_read_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { uint32_t addr, midpoint; @@ -2349,12 +2379,12 @@ qla2x00_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, } int -qla2x00_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +qla2x00_write_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { int rval; - uint8_t man_id, flash_id, sec_number, data; + uint8_t man_id, flash_id, sec_number, *data; uint16_t wd; uint32_t addr, liter, sec_mask, rest_addr; struct qla_hw_data *ha = vha->hw; @@ -2483,7 +2513,7 @@ update_flash: for (addr = offset, liter = 0; liter < length; liter++, addr++) { - data = buf[liter]; + data = buf + liter; /* Are we at the beginning of a sector? */ if ((addr & rest_addr) == 0) { if (IS_QLA2322(ha) || IS_QLA6322(ha)) { @@ -2551,7 +2581,7 @@ update_flash: } } - if (qla2x00_program_flash_address(ha, addr, data, + if (qla2x00_program_flash_address(ha, addr, *data, man_id, flash_id)) { rval = QLA_FUNCTION_FAILED; break; @@ -2567,8 +2597,8 @@ update_flash: return rval; } -uint8_t * -qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +void * +qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { struct qla_hw_data *ha = vha->hw; @@ -2578,7 +2608,7 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); /* Go with read. */ - qla24xx_read_flash_data(vha, (uint32_t *)buf, offset >> 2, length >> 2); + qla24xx_read_flash_data(vha, (void *)buf, offset >> 2, length >> 2); /* Resume HBA. */ clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); @@ -2587,8 +2617,340 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, return buf; } +static int +qla28xx_extract_sfub_and_verify(struct scsi_qla_host *vha, uint32_t *buf, + uint32_t len, uint32_t buf_size_without_sfub, uint8_t *sfub_buf) +{ + uint32_t *p, check_sum = 0; + int i; + + p = buf + buf_size_without_sfub; + + /* Extract SFUB from end of file */ + memcpy(sfub_buf, (uint8_t *)p, + sizeof(struct secure_flash_update_block)); + + for (i = 0; i < (sizeof(struct secure_flash_update_block) >> 2); i++) + check_sum += p[i]; + + check_sum = (~check_sum) + 1; + + if (check_sum != p[i]) { + ql_log(ql_log_warn, vha, 0x7097, + "SFUB checksum failed, 0x%x, 0x%x\n", + check_sum, p[i]); + return QLA_COMMAND_ERROR; + } + + return QLA_SUCCESS; +} + +static int +qla28xx_get_flash_region(struct scsi_qla_host *vha, uint32_t start, + struct qla_flt_region *region) +{ + struct qla_hw_data *ha = vha->hw; + struct qla_flt_header *flt; + struct qla_flt_region *flt_reg; + uint16_t cnt; + int rval = QLA_FUNCTION_FAILED; + + if (!ha->flt) + return QLA_FUNCTION_FAILED; + + flt = (struct qla_flt_header *)ha->flt; + flt_reg = (struct qla_flt_region *)&flt[1]; + cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); + + for (; cnt; cnt--, flt_reg++) { + if (flt_reg->start == start) { + memcpy((uint8_t *)region, flt_reg, + sizeof(struct qla_flt_region)); + rval = QLA_SUCCESS; + break; + } + } + + return rval; +} + +static int +qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, + uint32_t dwords) +{ + struct qla_hw_data *ha = vha->hw; + ulong liter; + ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */ + uint32_t sec_mask, rest_addr, fdata; + void *optrom = NULL; + dma_addr_t optrom_dma; + int rval; + struct secure_flash_update_block *sfub; + dma_addr_t sfub_dma; + uint32_t offset = faddr << 2; + uint32_t buf_size_without_sfub = 0; + struct qla_flt_region region; + bool reset_to_rom = false; + uint32_t risc_size, risc_attr = 0; + uint32_t *fw_array = NULL; + + /* Retrieve region info - must be a start address passed in */ + rval = qla28xx_get_flash_region(vha, offset, ®ion); + + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Invalid address %x - not a region start address\n", + offset); + goto done; + } + + /* Allocate dma buffer for burst write */ + optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + &optrom_dma, GFP_KERNEL); + if (!optrom) { + ql_log(ql_log_warn, vha, 0x7095, + "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE); + rval = QLA_COMMAND_ERROR; + goto done; + } + + /* + * If adapter supports secure flash and region is secure + * extract secure flash update block (SFUB) and verify + */ + if (ha->flags.secure_adapter && region.attribute) { + + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Region %x is secure\n", region.code); + + if (region.code == FLT_REG_FW || + region.code == FLT_REG_FW_SEC_27XX) { + fw_array = dwptr; + + /* 1st fw array */ + risc_size = be32_to_cpu(fw_array[3]); + risc_attr = be32_to_cpu(fw_array[9]); + + buf_size_without_sfub = risc_size; + fw_array += risc_size; + + /* 2nd fw array */ + risc_size = be32_to_cpu(fw_array[3]); + + buf_size_without_sfub += risc_size; + fw_array += risc_size; + + /* 1st dump template */ + risc_size = be32_to_cpu(fw_array[2]); + + /* skip header and ignore checksum */ + buf_size_without_sfub += risc_size; + fw_array += risc_size; + + if (risc_attr & BIT_9) { + /* 2nd dump template */ + risc_size = be32_to_cpu(fw_array[2]); + + /* skip header and ignore checksum */ + buf_size_without_sfub += risc_size; + fw_array += risc_size; + } + } else { + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Secure region %x not supported\n", + region.code); + rval = QLA_COMMAND_ERROR; + goto done; + } + + sfub = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct secure_flash_update_block), &sfub_dma, + GFP_KERNEL); + if (!sfub) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to allocate memory for SFUB\n"); + rval = QLA_COMMAND_ERROR; + goto done; + } + + rval = qla28xx_extract_sfub_and_verify(vha, dwptr, dwords, + buf_size_without_sfub, (uint8_t *)sfub); + + if (rval != QLA_SUCCESS) + goto done; + + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "SFUB extract and verify successful\n"); + } + + rest_addr = (ha->fdt_block_size >> 2) - 1; + sec_mask = ~rest_addr; + + /* Lock semaphore */ + rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to lock flash semaphore."); + goto done; + } + + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Unprotect flash...\n"); + rval = qla24xx_unprotect_flash(vha); + if (rval) { + qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); + ql_log(ql_log_warn, vha, 0x7096, "Failed unprotect flash\n"); + goto done; + } + + for (liter = 0; liter < dwords; liter++, faddr++) { + fdata = (faddr & sec_mask) << 2; + + /* If start of sector */ + if (!(faddr & rest_addr)) { + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Erase sector %#x...\n", faddr); + rval = qla24xx_erase_sector(vha, fdata); + if (rval) { + ql_dbg(ql_dbg_user, vha, 0x7007, + "Failed erase sector %#x\n", faddr); + goto write_protect; + } + } + } + + if (ha->flags.secure_adapter) { + /* + * If adapter supports secure flash but FW doesn't, + * disable write protect, release semaphore and reset + * chip to execute ROM code in order to update region securely + */ + if (!ha->flags.secure_fw) { + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Disable Write and Release Semaphore."); + rval = qla24xx_protect_flash(vha); + if (rval != QLA_SUCCESS) { + qla81xx_fac_semaphore_access(vha, + FAC_SEMAPHORE_UNLOCK); + ql_log(ql_log_warn, vha, 0xffff, + "Unable to protect flash."); + goto done; + } + + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Reset chip to ROM."); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + set_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + rval = qla2x00_wait_for_chip_reset(vha); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to reset to ROM code."); + goto done; + } + reset_to_rom = true; + ha->flags.fac_supported = 0; + + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Lock Semaphore"); + rval = qla2xxx_write_remote_register(vha, + FLASH_SEMAPHORE_REGISTER_ADDR, 0x00020002); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to lock flash semaphore."); + goto done; + } + + /* Unprotect flash */ + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Enable Write."); + rval = qla2x00_write_ram_word(vha, 0x7ffd0101, 0); + if (rval) { + ql_log(ql_log_warn, vha, 0x7096, + "Failed unprotect flash\n"); + goto done; + } + } + + /* If region is secure, send Secure Flash MB Cmd */ + if (region.attribute && buf_size_without_sfub) { + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff, + "Sending Secure Flash MB Cmd\n"); + rval = qla28xx_secure_flash_update(vha, 0, region.code, + buf_size_without_sfub, sfub_dma, + sizeof(struct secure_flash_update_block)); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Secure Flash MB Cmd failed %x.", rval); + goto write_protect; + } + } + + } + + /* re-init flash offset */ + faddr = offset >> 2; + + for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { + fdata = (faddr & sec_mask) << 2; + + /* If smaller than a burst remaining */ + if (dwords - liter < dburst) + dburst = dwords - liter; + + /* Copy to dma buffer */ + memcpy(optrom, dwptr, dburst << 2); + + /* Burst write */ + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Write burst (%#lx dwords)...\n", dburst); + rval = qla2x00_load_ram(vha, optrom_dma, + flash_data_addr(ha, faddr), dburst); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x7097, + "Failed burst write at %x (%p/%#llx)...\n", + flash_data_addr(ha, faddr), optrom, + (u64)optrom_dma); + break; + } + + liter += dburst - 1; + faddr += dburst - 1; + dwptr += dburst - 1; + continue; + } + +write_protect: + ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095, + "Protect flash...\n"); + rval = qla24xx_protect_flash(vha); + if (rval) { + qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); + ql_log(ql_log_warn, vha, 0x7099, + "Failed protect flash\n"); + } + + if (reset_to_rom == true) { + /* Schedule DPC to restart the RISC */ + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + + rval = qla2x00_wait_for_hba_online(vha); + if (rval != QLA_SUCCESS) + ql_log(ql_log_warn, vha, 0xffff, + "Adapter did not come out of reset\n"); + } + +done: + if (optrom) + dma_free_coherent(&ha->pdev->dev, + OPTROM_BURST_SIZE, optrom, optrom_dma); + + return rval; +} + int -qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { int rval; @@ -2599,8 +2961,12 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); /* Go with write. */ - rval = qla24xx_write_flash_data(vha, (uint32_t *)buf, offset >> 2, - length >> 2); + if (IS_QLA28XX(ha)) + rval = qla28xx_write_flash_data(vha, (uint32_t *)buf, + offset >> 2, length >> 2); + else + rval = qla24xx_write_flash_data(vha, (uint32_t *)buf, + offset >> 2, length >> 2); clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); scsi_unblock_requests(vha->host); @@ -2608,8 +2974,8 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, return rval; } -uint8_t * -qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, +void * +qla25xx_read_optrom_data(struct scsi_qla_host *vha, void *buf, uint32_t offset, uint32_t length) { int rval; @@ -2620,7 +2986,7 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, struct qla_hw_data *ha = vha->hw; if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || - IS_QLA27XX(ha)) + IS_QLA27XX(ha) || IS_QLA28XX(ha)) goto try_fast; if (offset & 0xfff) goto slow_read; @@ -2628,6 +2994,8 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, goto slow_read; try_fast: + if (offset & 0xff) + goto slow_read; optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, &optrom_dma, GFP_KERNEL); if (!optrom) { @@ -2874,7 +3242,7 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf) "Dumping fw " "ver from flash:.\n"); ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010b, - (uint8_t *)dbyte, 8); + dbyte, 32); if ((dcode[0] == 0xffff && dcode[1] == 0xffff && dcode[2] == 0xffff && dcode[3] == 0xffff) || @@ -2905,8 +3273,8 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) { int ret = QLA_SUCCESS; uint32_t pcihdr, pcids; - uint32_t *dcode; - uint8_t *bcode; + uint32_t *dcode = mbuf; + uint8_t *bcode = mbuf; uint8_t code_type, last_image; struct qla_hw_data *ha = vha->hw; @@ -2918,17 +3286,14 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - dcode = mbuf; - /* Begin with first PCI expansion ROM header. */ pcihdr = ha->flt_region_boot << 2; last_image = 1; do { /* Verify PCI expansion ROM header. */ - ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcihdr, - 0x20 * 4); + ha->isp_ops->read_optrom(vha, dcode, pcihdr, 0x20 * 4); bcode = mbuf + (pcihdr % 4); - if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) { + if (memcmp(bcode, "\x55\xaa", 2)) { /* No signature */ ql_log(ql_log_fatal, vha, 0x0154, "No matching ROM signature.\n"); @@ -2939,13 +3304,11 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) /* Locate PCI data structure. */ pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); - ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcids, - 0x20 * 4); + ha->isp_ops->read_optrom(vha, dcode, pcids, 0x20 * 4); bcode = mbuf + (pcihdr % 4); /* Validate signature of PCI data structure. */ - if (bcode[0x0] != 'P' || bcode[0x1] != 'C' || - bcode[0x2] != 'I' || bcode[0x3] != 'R') { + if (memcmp(bcode, "PCIR", 4)) { /* Incorrect header. */ ql_log(ql_log_fatal, vha, 0x0155, "PCI data struct not found pcir_adr=%x.\n", pcids); @@ -2996,8 +3359,7 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) /* Read firmware image information. */ memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); dcode = mbuf; - ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, ha->flt_region_fw << 2, - 0x20); + ha->isp_ops->read_optrom(vha, dcode, ha->flt_region_fw << 2, 0x20); bcode = mbuf + (pcihdr % 4); /* Validate signature of PCI data structure. */ @@ -3019,15 +3381,14 @@ int qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) { int ret = QLA_SUCCESS; - uint32_t pcihdr, pcids; - uint32_t *dcode; - uint8_t *bcode; + uint32_t pcihdr = 0, pcids = 0; + uint32_t *dcode = mbuf; + uint8_t *bcode = mbuf; uint8_t code_type, last_image; int i; struct qla_hw_data *ha = vha->hw; uint32_t faddr = 0; - - pcihdr = pcids = 0; + struct active_regions active_regions = { }; if (IS_P3P_TYPE(ha)) return ret; @@ -3040,18 +3401,19 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - dcode = mbuf; pcihdr = ha->flt_region_boot << 2; - if (IS_QLA27XX(ha) && - qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE) - pcihdr = ha->flt_region_boot_sec << 2; + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + qla27xx_get_active_image(vha, &active_regions); + if (active_regions.global == QLA27XX_SECONDARY_IMAGE) { + pcihdr = ha->flt_region_boot_sec << 2; + } + } - last_image = 1; do { /* Verify PCI expansion ROM header. */ qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20); bcode = mbuf + (pcihdr % 4); - if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) { + if (memcmp(bcode, "\x55\xaa", 2)) { /* No signature */ ql_log(ql_log_fatal, vha, 0x0059, "No matching ROM signature.\n"); @@ -3066,11 +3428,11 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) bcode = mbuf + (pcihdr % 4); /* Validate signature of PCI data structure. */ - if (bcode[0x0] != 'P' || bcode[0x1] != 'C' || - bcode[0x2] != 'I' || bcode[0x3] != 'R') { + if (memcmp(bcode, "PCIR", 4)) { /* Incorrect header. */ ql_log(ql_log_fatal, vha, 0x005a, "PCI data struct not found pcir_adr=%x.\n", pcids); + ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32); ret = QLA_FUNCTION_FAILED; break; } @@ -3117,30 +3479,24 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) /* Read firmware image information. */ memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - dcode = mbuf; faddr = ha->flt_region_fw; - if (IS_QLA27XX(ha) && - qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE) - faddr = ha->flt_region_fw_sec; - - qla24xx_read_flash_data(vha, dcode, faddr + 4, 4); - for (i = 0; i < 4; i++) - dcode[i] = be32_to_cpu(dcode[i]); + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + qla27xx_get_active_image(vha, &active_regions); + if (active_regions.global == QLA27XX_SECONDARY_IMAGE) + faddr = ha->flt_region_fw_sec; + } - if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && - dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { + qla24xx_read_flash_data(vha, dcode, faddr, 8); + if (qla24xx_risc_firmware_invalid(dcode)) { ql_log(ql_log_warn, vha, 0x005f, "Unrecognized fw revision at %x.\n", ha->flt_region_fw * 4); + ql_dump_buffer(ql_dbg_init, vha, 0x005f, dcode, 32); } else { - ha->fw_revision[0] = dcode[0]; - ha->fw_revision[1] = dcode[1]; - ha->fw_revision[2] = dcode[2]; - ha->fw_revision[3] = dcode[3]; + for (i = 0; i < 4; i++) + ha->fw_revision[i] = be32_to_cpu(dcode[4+i]); ql_dbg(ql_dbg_init, vha, 0x0060, - "Firmware revision %d.%d.%d (%x).\n", + "Firmware revision (flash) %u.%u.%u (%x).\n", ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2], ha->fw_revision[3]); } @@ -3152,20 +3508,17 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) } memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version)); - dcode = mbuf; - ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, - ha->flt_region_gold_fw << 2, 32); - - if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF && - dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) { + faddr = ha->flt_region_gold_fw; + qla24xx_read_flash_data(vha, (void *)dcode, ha->flt_region_gold_fw, 8); + if (qla24xx_risc_firmware_invalid(dcode)) { ql_log(ql_log_warn, vha, 0x0056, - "Unrecognized golden fw at 0x%x.\n", - ha->flt_region_gold_fw * 4); + "Unrecognized golden fw at %#x.\n", faddr); + ql_dump_buffer(ql_dbg_init, vha, 0x0056, dcode, 32); return ret; } - for (i = 4; i < 8; i++) - ha->gold_fw_version[i-4] = be32_to_cpu(dcode[i]); + for (i = 0; i < 4; i++) + ha->gold_fw_version[i] = be32_to_cpu(dcode[4+i]); return ret; } @@ -3237,7 +3590,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha) fcp_prio_addr = ha->flt_region_fcp_prio; /* first read the fcp priority data header from flash */ - ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg, + ha->isp_ops->read_optrom(vha, ha->fcp_prio_cfg, fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE); if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 0)) @@ -3248,7 +3601,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha) len = ha->fcp_prio_cfg->num_entries * FCP_PRIO_CFG_ENTRY_SIZE; max_len = FCP_PRIO_CFG_SIZE - FCP_PRIO_CFG_HDR_SIZE; - ha->isp_ops->read_optrom(vha, (uint8_t *)&ha->fcp_prio_cfg->entry[0], + ha->isp_ops->read_optrom(vha, &ha->fcp_prio_cfg->entry[0], fcp_prio_addr << 2, (len < max_len ? len : max_len)); /* revalidate the entire FCP priority config data, including entries */ diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 582d1663f971..1c1f63be6eed 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * qla_target.c SCSI LLD infrastructure for QLogic 22xx/23xx/24xx/25xx * @@ -11,16 +12,6 @@ * Forward port and refactoring to modern qla2xxx and target/configfs * * Copyright (C) 2010-2013 Nicholas A. Bellinger <nab@kernel.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, version 2 - * of the License. - * - * 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> @@ -184,6 +175,7 @@ static inline int qlt_issue_marker(struct scsi_qla_host *vha, int vha_locked) /* Send marker if required */ if (unlikely(vha->marker_needed != 0)) { int rc = qla2x00_issue_marker(vha, vha_locked); + if (rc != QLA_SUCCESS) { ql_dbg(ql_dbg_tgt, vha, 0xe03d, "qla_target(%d): issue_marker() failed\n", @@ -557,6 +549,7 @@ static int qla24xx_post_nack_work(struct scsi_qla_host *vha, fc_port_t *fcport, struct imm_ntfy_from_isp *ntfy, int type) { struct qla_work_evt *e; + e = qla2x00_alloc_work(vha, QLA_EVT_NACK); if (!e) return QLA_FUNCTION_FAILED; @@ -680,7 +673,6 @@ done: void qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e) { fc_port_t *t; - unsigned long flags; switch (e->u.nack.type) { case SRB_NACK_PRLI: @@ -693,24 +685,19 @@ void qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e) if (t) { ql_log(ql_log_info, vha, 0xd034, "%s create sess success %p", __func__, t); - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); /* create sess has an extra kref */ vha->hw->tgt.tgt_ops->put_sess(e->u.nack.fcport); - spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); } break; } qla24xx_async_notify_ack(vha, e->u.nack.fcport, - (struct imm_ntfy_from_isp*)e->u.nack.iocb, e->u.nack.type); + (struct imm_ntfy_from_isp *)e->u.nack.iocb, e->u.nack.type); } void qla24xx_delete_sess_fn(struct work_struct *work) { fc_port_t *fcport = container_of(work, struct fc_port, del_work); struct qla_hw_data *ha = fcport->vha->hw; - unsigned long flags; - - spin_lock_irqsave(&ha->tgt.sess_lock, flags); if (fcport->se_sess) { ha->tgt.tgt_ops->shutdown_sess(fcport); @@ -718,7 +705,6 @@ void qla24xx_delete_sess_fn(struct work_struct *work) } else { qlt_unreg_sess(fcport); } - spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); } /* @@ -787,8 +773,9 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) fcport->port_name, sess->loop_id); sess->local = 0; } - ha->tgt.tgt_ops->put_sess(sess); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + ha->tgt.tgt_ops->put_sess(sess); } /* @@ -980,6 +967,8 @@ void qlt_free_session_done(struct work_struct *work) sess->send_els_logo); if (!IS_SW_RESV_ADDR(sess->d_id)) { + qla2x00_mark_device_lost(vha, sess, 0, 0); + if (sess->send_els_logo) { qlt_port_logo_t logo; @@ -1015,6 +1004,12 @@ void qlt_free_session_done(struct work_struct *work) else logout_started = true; } + } /* if sess->logout_on_delete */ + + if (sess->nvme_flag & NVME_FLAG_REGISTERED && + !(sess->nvme_flag & NVME_FLAG_DELETING)) { + sess->nvme_flag |= NVME_FLAG_DELETING; + qla_nvme_unregister_remote_port(sess); } } @@ -1076,6 +1071,7 @@ void qlt_free_session_done(struct work_struct *work) struct qlt_plogi_ack_t *con = sess->plogi_link[QLT_PLOGI_LINK_CONFLICT]; struct imm_ntfy_from_isp *iocb; + own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; if (con) { @@ -1160,21 +1156,13 @@ void qlt_unreg_sess(struct fc_port *sess) if (sess->se_sess) vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); - qla2x00_mark_device_lost(vha, sess, 0, 0); - sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; sess->disc_state = DSC_DELETE_PEND; sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; - 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); - } else { - INIT_WORK(&sess->free_work, qlt_free_session_done); - schedule_work(&sess->free_work); - } + INIT_WORK(&sess->free_work, qlt_free_session_done); + schedule_work(&sess->free_work); } EXPORT_SYMBOL(qlt_unreg_sess); @@ -1329,6 +1317,7 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id, res = -ENOENT; for (i = 0; i < entries; i++) { struct gid_list_info *gid = (struct gid_list_info *)id_iter; + if ((gid->al_pa == s_id[2]) && (gid->area == s_id[1]) && (gid->domain == s_id[0])) { @@ -2331,14 +2320,14 @@ void qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, ctio->u.status1.scsi_status |= cpu_to_le16(SS_RESIDUAL_UNDER); - /* Response code and sense key */ - put_unaligned_le32(((0x70 << 24) | (sense_key << 8)), - (&ctio->u.status1.sense_data)[0]); + /* Fixed format sense data. */ + ctio->u.status1.sense_data[0] = 0x70; + ctio->u.status1.sense_data[2] = sense_key; /* Additional sense length */ - put_unaligned_le32(0x0a, (&ctio->u.status1.sense_data)[1]); + ctio->u.status1.sense_data[7] = 0xa; /* ASC and ASCQ */ - put_unaligned_le32(((asc << 24) | (ascq << 16)), - (&ctio->u.status1.sense_data)[3]); + ctio->u.status1.sense_data[12] = asc; + ctio->u.status1.sense_data[13] = ascq; /* Memory Barrier */ wmb(); @@ -2387,7 +2376,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) case ELS_PRLO: case ELS_TPRLO: ql_dbg(ql_dbg_disc, vha, 0x2106, - "TM response logo %phC status %#x state %#x", + "TM response logo %8phC status %#x state %#x", mcmd->sess->port_name, mcmd->fc_tm_rsp, mcmd->flags); qlt_schedule_sess_for_deletion(mcmd->sess); @@ -2485,6 +2474,7 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { struct qla_hw_data *ha; struct qla_qpair *qpair; + if (!cmd->sg_mapped) return; @@ -2635,7 +2625,7 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) { int cnt; - uint32_t *dword_ptr; + struct dsd64 *cur_dsd; /* Build continuation packets */ while (prm->seg_cnt > 0) { @@ -2656,19 +2646,13 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) cont_pkt64->sys_define = 0; cont_pkt64->entry_type = CONTINUE_A64_TYPE; - dword_ptr = (uint32_t *)&cont_pkt64->dseg_0_address; + cur_dsd = cont_pkt64->dsd; /* Load continuation entry data segments */ for (cnt = 0; cnt < QLA_TGT_DATASEGS_PER_CONT_24XX && prm->seg_cnt; cnt++, prm->seg_cnt--) { - *dword_ptr++ = - cpu_to_le32(lower_32_bits - (sg_dma_address(prm->sg))); - *dword_ptr++ = cpu_to_le32(upper_32_bits - (sg_dma_address(prm->sg))); - *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); - + append_dsd64(&cur_dsd, prm->sg); prm->sg = sg_next(prm->sg); } } @@ -2681,13 +2665,13 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) static void qlt_load_data_segments(struct qla_tgt_prm *prm) { int cnt; - uint32_t *dword_ptr; + struct dsd64 *cur_dsd; struct ctio7_to_24xx *pkt24 = (struct ctio7_to_24xx *)prm->pkt; pkt24->u.status0.transfer_length = cpu_to_le32(prm->cmd->bufflen); /* Setup packet address segment pointer */ - dword_ptr = pkt24->u.status0.dseg_0_address; + cur_dsd = &pkt24->u.status0.dsd; /* Set total data segment count */ if (prm->seg_cnt) @@ -2695,8 +2679,8 @@ static void qlt_load_data_segments(struct qla_tgt_prm *prm) if (prm->seg_cnt == 0) { /* No data transfer */ - *dword_ptr++ = 0; - *dword_ptr = 0; + cur_dsd->address = 0; + cur_dsd->length = 0; return; } @@ -2706,14 +2690,7 @@ static void qlt_load_data_segments(struct qla_tgt_prm *prm) for (cnt = 0; (cnt < QLA_TGT_DATASEGS_PER_CMD_24XX) && prm->seg_cnt; cnt++, prm->seg_cnt--) { - *dword_ptr++ = - cpu_to_le32(lower_32_bits(sg_dma_address(prm->sg))); - - *dword_ptr++ = cpu_to_le32(upper_32_bits( - sg_dma_address(prm->sg))); - - *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); - + append_dsd64(&cur_dsd, prm->sg); prm->sg = sg_next(prm->sg); } @@ -3037,7 +3014,7 @@ qla_tgt_set_dif_tags(struct qla_tgt_cmd *cmd, struct crc_context *ctx, static inline int qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) { - uint32_t *cur_dsd; + struct dsd64 *cur_dsd; uint32_t transfer_length = 0; uint32_t data_bytes; uint32_t dif_bytes; @@ -3183,12 +3160,11 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) qla_tgt_set_dif_tags(cmd, crc_ctx_pkt, &fw_prot_opts); - pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma)); - pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma)); + put_unaligned_le64(crc_ctx_dma, &pkt->crc_context_address); pkt->crc_context_len = CRC_CONTEXT_LEN_FW; if (!bundling) { - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address; + cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd; } else { /* * Configure Bundling if we need to fetch interlaving @@ -3198,7 +3174,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(prm->tot_dsds - prm->prot_seg_cnt); - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address; + cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd; } /* Finish the common fields of CRC pkt */ @@ -3231,7 +3207,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) /* Walks dif segments */ pkt->add_flags |= CTIO_CRC2_AF_DIF_DSD_ENA; - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; + cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd; if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd, prm->prot_seg_cnt, cmd)) goto crc_queuing_error; @@ -3263,7 +3239,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || (cmd->sess && cmd->sess->deleted)) { cmd->state = QLA_TGT_STATE_PROCESSED; - qlt_abort_cmd_on_host_reset(cmd->vha, cmd); return 0; } @@ -3292,7 +3267,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, * previous life, just abort the processing. */ cmd->state = QLA_TGT_STATE_PROCESSED; - qlt_abort_cmd_on_host_reset(cmd->vha, cmd); ql_dbg_qp(ql_dbg_async, qpair, 0xe101, "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), @@ -3384,9 +3358,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */ - spin_lock(&cmd->cmd_lock); cmd->cmd_sent_to_fw = 1; - spin_unlock(&cmd->cmd_lock); cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ @@ -3433,8 +3405,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) * Either the port is not online or this request was from * previous life, just abort the processing. */ - cmd->state = QLA_TGT_STATE_NEED_DATA; - qlt_abort_cmd_on_host_reset(cmd->vha, cmd); + cmd->aborted = 1; + cmd->write_data_transferred = 0; + cmd->state = QLA_TGT_STATE_DATA_IN; + vha->hw->tgt.tgt_ops->handle_data(cmd); ql_dbg_qp(ql_dbg_async, qpair, 0xe102, "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), @@ -3465,9 +3439,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) qlt_load_data_segments(&prm); cmd->state = QLA_TGT_STATE_NEED_DATA; - spin_lock(&cmd->cmd_lock); cmd->cmd_sent_to_fw = 1; - spin_unlock(&cmd->cmd_lock); cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ @@ -3646,33 +3618,11 @@ static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha, static void qlt_send_term_imm_notif(struct scsi_qla_host *vha, struct imm_ntfy_from_isp *imm, int ha_locked) { - unsigned long flags = 0; int rc; - if (ha_locked) { - rc = __qlt_send_term_imm_notif(vha, imm); - -#if 0 /* Todo */ - if (rc == -ENOMEM) - qlt_alloc_qfull_cmd(vha, imm, 0, 0); -#else - if (rc) { - } -#endif - goto done; - } - - spin_lock_irqsave(&vha->hw->hardware_lock, flags); + WARN_ON_ONCE(!ha_locked); rc = __qlt_send_term_imm_notif(vha, imm); - -#if 0 /* Todo */ - if (rc == -ENOMEM) - qlt_alloc_qfull_cmd(vha, imm, 0, 0); -#endif - -done: - if (!ha_locked) - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); + pr_debug("rc = %d\n", rc); } /* @@ -3913,6 +3863,7 @@ static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, if (ctio != NULL) { struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio; + term = !(c->flags & cpu_to_le16(OF_TERM_EXCH)); } else @@ -3977,39 +3928,6 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, return cmd; } -/* hardware_lock should be held by caller. */ -void -qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) -{ - struct qla_hw_data *ha = vha->hw; - - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - - /* TODO: fix debug message type and ids. */ - if (cmd->state == QLA_TGT_STATE_PROCESSED) { - ql_dbg(ql_dbg_io, vha, 0xff00, - "HOST-ABORT: state=PROCESSED.\n"); - } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { - cmd->write_data_transferred = 0; - cmd->state = QLA_TGT_STATE_DATA_IN; - - ql_dbg(ql_dbg_io, vha, 0xff01, - "HOST-ABORT: state=DATA_IN.\n"); - - ha->tgt.tgt_ops->handle_data(cmd); - return; - } else { - ql_dbg(ql_dbg_io, vha, 0xff03, - "HOST-ABORT: state=BAD(%d).\n", - cmd->state); - dump_stack(); - } - - cmd->trc_flags |= TRC_FLUSH; - ha->tgt.tgt_ops->free_cmd(cmd); -} - /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ @@ -4031,7 +3949,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, return; } - cmd = (struct qla_tgt_cmd *)qlt_ctio_to_cmd(vha, rsp, handle, ctio); + cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); if (cmd == NULL) return; @@ -4240,11 +4158,9 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) if (ret != 0) goto out_term; /* - * Drop extra session reference from qla_tgt_handle_cmd_for_atio*( + * Drop extra session reference from qlt_handle_cmd_for_atio(). */ - spin_lock_irqsave(&ha->tgt.sess_lock, flags); ha->tgt.tgt_ops->put_sess(sess); - spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); return; out_term: @@ -4261,9 +4177,7 @@ out_term: target_free_tag(sess->se_sess, &cmd->se_cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - spin_lock_irqsave(&ha->tgt.sess_lock, flags); ha->tgt.tgt_ops->put_sess(sess); - spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); } static void qlt_do_work(struct work_struct *work) @@ -4472,9 +4386,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, if (!cmd) { ql_dbg(ql_dbg_io, vha, 0x3062, "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); - spin_lock_irqsave(&ha->tgt.sess_lock, flags); ha->tgt.tgt_ops->put_sess(sess); - spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); return -EBUSY; } @@ -4773,6 +4685,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id) list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) { uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); + if (op_key == key) { op->aborted = true; count++; @@ -4781,6 +4694,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id) list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); + if (cmd_key == key) { cmd->aborted = 1; count++; @@ -5051,6 +4965,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, if (sess != NULL) { bool delete = false; int sec; + spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags); switch (sess->fw_login_state) { case DSC_LS_PLOGI_PEND: @@ -5203,6 +5118,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, case ELS_ADISC: { struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + if (tgt->link_reinit_iocb_pending) { qlt_send_notify_ack(ha->base_qpair, &tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0); @@ -5266,6 +5182,7 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha, case IMM_NTFY_LIP_LINK_REINIT: { struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf033, "qla_target(%d): LINK REINIT (loop %#x, " "subcode %x)\n", vha->vp_idx, @@ -5492,11 +5409,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, se_sess = sess->se_sess; tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); - if (tag < 0) - return; - - cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; - if (!cmd) { + if (tag < 0) { ql_dbg(ql_dbg_io, vha, 0x3009, "qla_target(%d): %s: Allocation of cmd failed\n", vha->vp_idx, __func__); @@ -5511,6 +5424,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, return; } + cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; memset(cmd, 0, sizeof(struct qla_tgt_cmd)); qlt_incr_num_pend_cmds(vha); @@ -5820,8 +5734,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, struct qla_tgt_mgmt_cmd *mcmd; struct qla_hw_data *ha = vha->hw; - mcmd = (struct qla_tgt_mgmt_cmd *)qlt_ctio_to_cmd(vha, rsp, - pkt->handle, pkt); + mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, pkt); if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) { ql_dbg(ql_dbg_async, vha, 0xe064, "qla_target(%d): ABTS Comp without mcmd\n", @@ -5883,6 +5796,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, case CTIO_TYPE7: { struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt; + qlt_do_ctio_completion(vha, rsp, entry->handle, le16_to_cpu(entry->status)|(pkt->entry_status << 16), entry); @@ -5893,6 +5807,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, { struct atio_from_isp *atio = (struct atio_from_isp *)pkt; int rc; + if (atio->u.isp2x.status != cpu_to_le16(ATIO_CDB_VALID)) { ql_dbg(ql_dbg_tgt, vha, 0xe05e, @@ -5941,6 +5856,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, case CONTINUE_TGT_IO_TYPE: { struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; + qlt_do_ctio_completion(vha, rsp, entry->handle, le16_to_cpu(entry->status)|(pkt->entry_status << 16), entry); @@ -5950,6 +5866,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, case CTIO_A64_TYPE: { struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; + qlt_do_ctio_completion(vha, rsp, entry->handle, le16_to_cpu(entry->status)|(pkt->entry_status << 16), entry); @@ -5964,6 +5881,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, case NOTIFY_ACK_TYPE: if (tgt->notify_ack_expected > 0) { struct nack_to_isp *entry = (struct nack_to_isp *)pkt; + ql_dbg(ql_dbg_tgt, vha, 0xe036, "NOTIFY_ACK seq %08x status %x\n", le16_to_cpu(entry->u.isp2x.seq_id), @@ -6239,6 +6157,7 @@ retry: if (rc == -ENOENT) { qlt_port_logo_t logo; + sid_to_portid(s_id, &logo.id); logo.cmd_count = 1; qlt_send_first_logo(vha, &logo); @@ -6318,17 +6237,19 @@ static void qlt_abort_work(struct qla_tgt *tgt, } rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); - ha->tgt.tgt_ops->put_sess(sess); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); + ha->tgt.tgt_ops->put_sess(sess); + if (rc != 0) goto out_term; return; out_term2: + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); + if (sess) ha->tgt.tgt_ops->put_sess(sess); - spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); out_term: spin_lock_irqsave(&ha->hardware_lock, flags); @@ -6386,9 +6307,10 @@ static void qlt_tmr_work(struct qla_tgt *tgt, scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun); rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); - ha->tgt.tgt_ops->put_sess(sess); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + ha->tgt.tgt_ops->put_sess(sess); + if (rc != 0) goto out_term; return; @@ -6499,6 +6421,7 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) unsigned long flags; struct qla_qpair *qpair = ha->queue_pair_map[i]; + h = &tgt->qphints[i + 1]; INIT_LIST_HEAD(&h->hint_elem); if (qpair) { @@ -6937,7 +6860,7 @@ qlt_24xx_config_rings(struct scsi_qla_host *vha) RD_REG_DWORD(ISP_ATIO_Q_OUT(vha)); if (ha->flags.msix_enabled) { - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { if (IS_QLA2071(ha)) { /* 4 ports Baker: Enable Interrupt Handshake */ icb->msix_atio = 0; @@ -6952,7 +6875,7 @@ qlt_24xx_config_rings(struct scsi_qla_host *vha) } } else { /* INTx|MSI */ - if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { icb->msix_atio = 0; icb->firmware_options_2 |= BIT_26; ql_dbg(ql_dbg_init, vha, 0xf072, @@ -7201,7 +7124,8 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) if (!QLA_TGT_MODE_ENABLED()) return; - if ((ql2xenablemsix == 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { + if ((ql2xenablemsix == 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in; ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out; } else { @@ -7329,7 +7253,10 @@ qlt_mem_free(struct qla_hw_data *ha) sizeof(struct atio_from_isp), ha->tgt.atio_ring, ha->tgt.atio_dma); } + ha->tgt.atio_ring = NULL; + ha->tgt.atio_dma = 0; kfree(ha->tgt.tgt_vp_map); + ha->tgt.tgt_vp_map = NULL; } /* vport_slock to be held by the caller */ @@ -7413,6 +7340,9 @@ int __init qlt_init(void) { int ret; + BUILD_BUG_ON(sizeof(struct ctio7_to_24xx) != 64); + BUILD_BUG_ON(sizeof(struct ctio_to_2xxx) != 64); + if (!qlt_parse_ini_mode()) { ql_log(ql_log_fatal, NULL, 0xe06b, "qlt_parse_ini_mode() failed\n"); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index f3de75000a08..b8d244f1e189 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2004 - 2010 Vladislav Bolkhovitin <vst@vlnb.net> * Copyright (C) 2004 - 2005 Leonid Stoljar @@ -9,16 +10,6 @@ * Copyright (C) 2010-2011 Nicholas A. Bellinger <nab@kernel.org> * * Additional file for the target driver support. - * - * 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. */ /* * This is the global def file that is useful for including from the @@ -29,6 +20,7 @@ #define __QLA_TARGET_H #include "qla_def.h" +#include "qla_dsd.h" /* * Must be changed on any change in any initiator visible interfaces or @@ -224,12 +216,7 @@ struct ctio_to_2xxx { uint16_t reserved_1[3]; uint16_t scsi_status; uint32_t transfer_length; - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ + struct dsd32 dsd[3]; } __packed; #define ATIO_PATH_INVALID 0x07 #define ATIO_CANT_PROV_CAP 0x16 @@ -429,10 +416,7 @@ struct ctio7_to_24xx { uint32_t reserved2; uint32_t transfer_length; uint32_t reserved3; - /* Data segment 0 address. */ - uint32_t dseg_0_address[2]; - /* Data segment 0 length. */ - uint32_t dseg_0_length; + struct dsd64 dsd; } status0; struct { uint16_t sense_length; @@ -526,10 +510,10 @@ struct ctio_crc2_to_fw { uint32_t reserved5; __le32 transfer_length; /* total fc transfer length */ uint32_t reserved6; - __le32 crc_context_address[2];/* Data segment address. */ + __le64 crc_context_address __packed; /* Data segment address. */ uint16_t crc_context_len; /* Data segment length. */ uint16_t reserved_1; /* MUST be set to 0. */ -} __packed; +}; /* CTIO Type CRC_x Status IOCB */ struct ctio_crc_from_fw { @@ -855,7 +839,7 @@ enum trace_flags { TRC_CTIO_ERR = BIT_11, TRC_CTIO_DONE = BIT_12, TRC_CTIO_ABORTED = BIT_13, - TRC_CTIO_STRANGE= BIT_14, + TRC_CTIO_STRANGE = BIT_14, TRC_CMD_DONE = BIT_15, TRC_CMD_CHK_STOP = BIT_16, TRC_CMD_FREE = BIT_17, @@ -889,10 +873,14 @@ struct qla_tgt_cmd { unsigned int term_exchg:1; unsigned int cmd_sent_to_fw:1; unsigned int cmd_in_wq:1; - unsigned int aborted:1; - unsigned int data_work:1; - unsigned int data_work_free:1; - unsigned int released:1; + + /* + * This variable may be set from outside the LIO and I/O completion + * callback functions. Do not declare this member variable as a + * bitfield to avoid a read-modify-write operation when this variable + * is set. + */ + unsigned int aborted; struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ @@ -1103,7 +1091,5 @@ extern void qlt_do_generation_tick(struct scsi_qla_host *, int *); void qlt_send_resp_ctio(struct qla_qpair *, struct qla_tgt_cmd *, uint8_t, uint8_t, uint8_t, uint8_t); -extern void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *, - struct qla_tgt_cmd *); #endif /* __QLA_TARGET_H */ diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 9e52500caff0..de696a07532e 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -7,103 +7,9 @@ #include "qla_def.h" #include "qla_tmpl.h" -/* note default template is in big endian */ -static const uint32_t ql27xx_fwdt_default_template[] = { - 0x63000000, 0xa4000000, 0x7c050000, 0x00000000, - 0x30000000, 0x01000000, 0x00000000, 0xc0406eb4, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x04010000, 0x14000000, 0x00000000, - 0x02000000, 0x44000000, 0x09010000, 0x10000000, - 0x00000000, 0x02000000, 0x01010000, 0x1c000000, - 0x00000000, 0x02000000, 0x00600000, 0x00000000, - 0xc0000000, 0x01010000, 0x1c000000, 0x00000000, - 0x02000000, 0x00600000, 0x00000000, 0xcc000000, - 0x01010000, 0x1c000000, 0x00000000, 0x02000000, - 0x10600000, 0x00000000, 0xd4000000, 0x01010000, - 0x1c000000, 0x00000000, 0x02000000, 0x700f0000, - 0x00000060, 0xf0000000, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x00700000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x10700000, 0x041000c0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x40700000, 0x041000c0, - 0x01010000, 0x1c000000, 0x00000000, 0x02000000, - 0x007c0000, 0x01000000, 0xc0000000, 0x00010000, - 0x18000000, 0x00000000, 0x02000000, 0x007c0000, - 0x040300c4, 0x00010000, 0x18000000, 0x00000000, - 0x02000000, 0x007c0000, 0x040100c0, 0x01010000, - 0x1c000000, 0x00000000, 0x02000000, 0x007c0000, - 0x00000000, 0xc0000000, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x007c0000, 0x04200000, - 0x0b010000, 0x18000000, 0x00000000, 0x02000000, - 0x0c000000, 0x00000000, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000000b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000010b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000020b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000030b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000040b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000050b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000060b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000070b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000080b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x000090b0, 0x02010000, 0x20000000, - 0x00000000, 0x02000000, 0x700f0000, 0x040100fc, - 0xf0000000, 0x0000a0b0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x0a000000, 0x040100c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x0a000000, 0x04200080, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x00be0000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x10be0000, 0x041000c0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x20be0000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x30be0000, 0x041000c0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x00b00000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x10b00000, 0x041000c0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x20b00000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x30b00000, 0x041000c0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x00300000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x10300000, 0x041000c0, 0x00010000, 0x18000000, - 0x00000000, 0x02000000, 0x20300000, 0x041000c0, - 0x00010000, 0x18000000, 0x00000000, 0x02000000, - 0x30300000, 0x041000c0, 0x0a010000, 0x10000000, - 0x00000000, 0x02000000, 0x06010000, 0x1c000000, - 0x00000000, 0x02000000, 0x01000000, 0x00000200, - 0xff230200, 0x06010000, 0x1c000000, 0x00000000, - 0x02000000, 0x02000000, 0x00001000, 0x00000000, - 0x07010000, 0x18000000, 0x00000000, 0x02000000, - 0x00000000, 0x01000000, 0x07010000, 0x18000000, - 0x00000000, 0x02000000, 0x00000000, 0x02000000, - 0x07010000, 0x18000000, 0x00000000, 0x02000000, - 0x00000000, 0x03000000, 0x0d010000, 0x14000000, - 0x00000000, 0x02000000, 0x00000000, 0xff000000, - 0x10000000, 0x00000000, 0x00000080, -}; - -static inline void __iomem * -qla27xx_isp_reg(struct scsi_qla_host *vha) -{ - return &vha->hw->iobase->isp24; -} +#define ISPREG(vha) (&(vha)->hw->iobase->isp24) +#define IOBAR(reg) offsetof(typeof(*(reg)), iobase_addr) +#define IOBASE(vha) IOBAR(ISPREG(vha)) static inline void qla27xx_insert16(uint16_t value, void *buf, ulong *len) @@ -128,7 +34,6 @@ qla27xx_insert32(uint32_t value, void *buf, ulong *len) static inline void qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len) { - if (buf && mem && size) { buf += *len; memcpy(buf, mem, size); @@ -190,9 +95,9 @@ static inline void qla27xx_write_reg(__iomem struct device_reg_24xx *reg, uint offset, uint32_t data, void *buf) { - __iomem void *window = (void __iomem *)reg + offset; - if (buf) { + void __iomem *window = (void __iomem *)reg + offset; + WRT_REG_DWORD(window, data); } } @@ -205,7 +110,7 @@ qla27xx_read_window(__iomem struct device_reg_24xx *reg, void __iomem *window = (void __iomem *)reg + offset; void (*readn)(void __iomem*, void *, ulong *) = qla27xx_read_vector(width); - qla27xx_write_reg(reg, IOBASE_ADDR, addr, buf); + qla27xx_write_reg(reg, IOBAR(reg), addr, buf); while (count--) { qla27xx_insert32(addr, buf, len); readn(window, buf, len); @@ -224,7 +129,7 @@ qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf) static inline struct qla27xx_fwdt_entry * qla27xx_next_entry(struct qla27xx_fwdt_entry *ent) { - return (void *)ent + ent->hdr.size; + return (void *)ent + le32_to_cpu(ent->hdr.size); } static struct qla27xx_fwdt_entry * @@ -254,12 +159,14 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + ulong addr = le32_to_cpu(ent->t256.base_addr); + uint offset = ent->t256.pci_offset; + ulong count = le16_to_cpu(ent->t256.reg_count); + uint width = ent->t256.reg_width; ql_dbg(ql_dbg_misc, vha, 0xd200, "%s: rdio t1 [%lx]\n", __func__, *len); - qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset, - ent->t256.reg_count, ent->t256.reg_width, buf, len); + qla27xx_read_window(ISPREG(vha), addr, offset, count, width, buf, len); return qla27xx_next_entry(ent); } @@ -268,12 +175,14 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + ulong addr = le32_to_cpu(ent->t257.base_addr); + uint offset = ent->t257.pci_offset; + ulong data = le32_to_cpu(ent->t257.write_data); ql_dbg(ql_dbg_misc, vha, 0xd201, "%s: wrio t1 [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf); - qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf); + qla27xx_write_reg(ISPREG(vha), IOBASE(vha), addr, buf); + qla27xx_write_reg(ISPREG(vha), offset, data, buf); return qla27xx_next_entry(ent); } @@ -282,13 +191,17 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + uint banksel = ent->t258.banksel_offset; + ulong bank = le32_to_cpu(ent->t258.bank); + ulong addr = le32_to_cpu(ent->t258.base_addr); + uint offset = ent->t258.pci_offset; + uint count = le16_to_cpu(ent->t258.reg_count); + uint width = ent->t258.reg_width; ql_dbg(ql_dbg_misc, vha, 0xd202, "%s: rdio t2 [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, ent->t258.banksel_offset, ent->t258.bank, buf); - qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset, - ent->t258.reg_count, ent->t258.reg_width, buf, len); + qla27xx_write_reg(ISPREG(vha), banksel, bank, buf); + qla27xx_read_window(ISPREG(vha), addr, offset, count, width, buf, len); return qla27xx_next_entry(ent); } @@ -297,13 +210,17 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + ulong addr = le32_to_cpu(ent->t259.base_addr); + uint banksel = ent->t259.banksel_offset; + ulong bank = le32_to_cpu(ent->t259.bank); + uint offset = ent->t259.pci_offset; + ulong data = le32_to_cpu(ent->t259.write_data); ql_dbg(ql_dbg_misc, vha, 0xd203, "%s: wrio t2 [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, IOBASE_ADDR, ent->t259.base_addr, buf); - qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf); - qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf); + qla27xx_write_reg(ISPREG(vha), IOBASE(vha), addr, buf); + qla27xx_write_reg(ISPREG(vha), banksel, bank, buf); + qla27xx_write_reg(ISPREG(vha), offset, data, buf); return qla27xx_next_entry(ent); } @@ -312,12 +229,12 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + uint offset = ent->t260.pci_offset; ql_dbg(ql_dbg_misc, vha, 0xd204, "%s: rdpci [%lx]\n", __func__, *len); - qla27xx_insert32(ent->t260.pci_offset, buf, len); - qla27xx_read_reg(reg, ent->t260.pci_offset, buf, len); + qla27xx_insert32(offset, buf, len); + qla27xx_read_reg(ISPREG(vha), offset, buf, len); return qla27xx_next_entry(ent); } @@ -326,11 +243,12 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + uint offset = ent->t261.pci_offset; + ulong data = le32_to_cpu(ent->t261.write_data); ql_dbg(ql_dbg_misc, vha, 0xd205, "%s: wrpci [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, ent->t261.pci_offset, ent->t261.write_data, buf); + qla27xx_write_reg(ISPREG(vha), offset, data, buf); return qla27xx_next_entry(ent); } @@ -339,51 +257,50 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { + uint area = ent->t262.ram_area; + ulong start = le32_to_cpu(ent->t262.start_addr); + ulong end = le32_to_cpu(ent->t262.end_addr); ulong dwords; - ulong start; - ulong end; ql_dbg(ql_dbg_misc, vha, 0xd206, "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len); - start = ent->t262.start_addr; - end = ent->t262.end_addr; - if (ent->t262.ram_area == T262_RAM_AREA_CRITICAL_RAM) { + if (area == T262_RAM_AREA_CRITICAL_RAM) { ; - } else if (ent->t262.ram_area == T262_RAM_AREA_EXTERNAL_RAM) { + } else if (area == T262_RAM_AREA_EXTERNAL_RAM) { end = vha->hw->fw_memory_size; if (buf) - ent->t262.end_addr = end; - } else if (ent->t262.ram_area == T262_RAM_AREA_SHARED_RAM) { + ent->t262.end_addr = cpu_to_le32(end); + } else if (area == T262_RAM_AREA_SHARED_RAM) { start = vha->hw->fw_shared_ram_start; end = vha->hw->fw_shared_ram_end; if (buf) { - ent->t262.start_addr = start; - ent->t262.end_addr = end; + ent->t262.start_addr = cpu_to_le32(start); + ent->t262.end_addr = cpu_to_le32(end); } - } else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) { + } else if (area == T262_RAM_AREA_DDR_RAM) { start = vha->hw->fw_ddr_ram_start; end = vha->hw->fw_ddr_ram_end; if (buf) { - ent->t262.start_addr = start; - ent->t262.end_addr = end; + ent->t262.start_addr = cpu_to_le32(start); + ent->t262.end_addr = cpu_to_le32(end); } - } else if (ent->t262.ram_area == T262_RAM_AREA_MISC) { + } else if (area == T262_RAM_AREA_MISC) { if (buf) { - ent->t262.start_addr = start; - ent->t262.end_addr = end; + ent->t262.start_addr = cpu_to_le32(start); + ent->t262.end_addr = cpu_to_le32(end); } } else { ql_dbg(ql_dbg_misc, vha, 0xd022, - "%s: unknown area %x\n", __func__, ent->t262.ram_area); + "%s: unknown area %x\n", __func__, area); qla27xx_skip_entry(ent, buf); goto done; } if (end < start || start == 0 || end == 0) { ql_dbg(ql_dbg_misc, vha, 0xd023, - "%s: unusable range (start=%x end=%x)\n", __func__, - ent->t262.end_addr, ent->t262.start_addr); + "%s: unusable range (start=%lx end=%lx)\n", + __func__, start, end); qla27xx_skip_entry(ent, buf); goto done; } @@ -402,13 +319,14 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { + uint type = ent->t263.queue_type; uint count = 0; uint i; uint length; - ql_dbg(ql_dbg_misc, vha, 0xd207, - "%s: getq(%x) [%lx]\n", __func__, ent->t263.queue_type, *len); - if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) { + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd207, + "%s: getq(%x) [%lx]\n", __func__, type, *len); + if (type == T263_QUEUE_TYPE_REQ) { for (i = 0; i < vha->hw->max_req_queues; i++) { struct req_que *req = vha->hw->req_q_map[i]; @@ -422,7 +340,7 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, count++; } } - } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) { + } else if (type == T263_QUEUE_TYPE_RSP) { for (i = 0; i < vha->hw->max_rsp_queues; i++) { struct rsp_que *rsp = vha->hw->rsp_q_map[i]; @@ -450,7 +368,7 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, } } else { ql_dbg(ql_dbg_misc, vha, 0xd026, - "%s: unknown queue %x\n", __func__, ent->t263.queue_type); + "%s: unknown queue %x\n", __func__, type); qla27xx_skip_entry(ent, buf); } @@ -496,12 +414,10 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); - - ql_dbg(ql_dbg_misc, vha, 0xd209, + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd209, "%s: pause risc [%lx]\n", __func__, *len); if (buf) - qla24xx_pause_risc(reg, vha->hw); + qla24xx_pause_risc(ISPREG(vha), vha->hw); return qla27xx_next_entry(ent); } @@ -522,11 +438,12 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + uint offset = ent->t267.pci_offset; + ulong data = le32_to_cpu(ent->t267.data); ql_dbg(ql_dbg_misc, vha, 0xd20b, "%s: dis intr [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf); + qla27xx_write_reg(ISPREG(vha), offset, data, buf); return qla27xx_next_entry(ent); } @@ -622,17 +539,16 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); - ulong dwords = ent->t270.count; - ulong addr = ent->t270.addr; + ulong addr = le32_to_cpu(ent->t270.addr); + ulong dwords = le32_to_cpu(ent->t270.count); ql_dbg(ql_dbg_misc, vha, 0xd20e, "%s: rdremreg [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf); + qla27xx_write_reg(ISPREG(vha), IOBASE_ADDR, 0x40, buf); while (dwords--) { - qla27xx_write_reg(reg, 0xc0, addr|0x80000000, buf); + qla27xx_write_reg(ISPREG(vha), 0xc0, addr|0x80000000, buf); qla27xx_insert32(addr, buf, len); - qla27xx_read_reg(reg, 0xc4, buf, len); + qla27xx_read_reg(ISPREG(vha), 0xc4, buf, len); addr += sizeof(uint32_t); } @@ -643,15 +559,14 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); - ulong addr = ent->t271.addr; - ulong data = ent->t271.data; + ulong addr = le32_to_cpu(ent->t271.addr); + ulong data = le32_to_cpu(ent->t271.data); ql_dbg(ql_dbg_misc, vha, 0xd20f, "%s: wrremreg [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf); - qla27xx_write_reg(reg, 0xc4, data, buf); - qla27xx_write_reg(reg, 0xc0, addr, buf); + qla27xx_write_reg(ISPREG(vha), IOBASE(vha), 0x40, buf); + qla27xx_write_reg(ISPREG(vha), 0xc4, data, buf); + qla27xx_write_reg(ISPREG(vha), 0xc0, addr, buf); return qla27xx_next_entry(ent); } @@ -660,8 +575,8 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - ulong dwords = ent->t272.count; - ulong start = ent->t272.addr; + ulong dwords = le32_to_cpu(ent->t272.count); + ulong start = le32_to_cpu(ent->t272.addr); ql_dbg(ql_dbg_misc, vha, 0xd210, "%s: rdremram [%lx]\n", __func__, *len); @@ -680,8 +595,8 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - ulong dwords = ent->t273.count; - ulong addr = ent->t273.addr; + ulong dwords = le32_to_cpu(ent->t273.count); + ulong addr = le32_to_cpu(ent->t273.addr); uint32_t value; ql_dbg(ql_dbg_misc, vha, 0xd211, @@ -703,12 +618,13 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { + ulong type = ent->t274.queue_type; uint count = 0; uint i; - ql_dbg(ql_dbg_misc, vha, 0xd212, - "%s: getqsh(%x) [%lx]\n", __func__, ent->t274.queue_type, *len); - if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) { + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd212, + "%s: getqsh(%lx) [%lx]\n", __func__, type, *len); + if (type == T274_QUEUE_TYPE_REQ_SHAD) { for (i = 0; i < vha->hw->max_req_queues; i++) { struct req_que *req = vha->hw->req_q_map[i]; @@ -720,7 +636,7 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, count++; } } - } else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) { + } else if (type == T274_QUEUE_TYPE_RSP_SHAD) { for (i = 0; i < vha->hw->max_rsp_queues; i++) { struct rsp_que *rsp = vha->hw->rsp_q_map[i]; @@ -746,7 +662,7 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, } } else { ql_dbg(ql_dbg_misc, vha, 0xd02f, - "%s: unknown queue %x\n", __func__, ent->t274.queue_type); + "%s: unknown queue %lx\n", __func__, type); qla27xx_skip_entry(ent, buf); } @@ -765,23 +681,26 @@ qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { ulong offset = offsetof(typeof(*ent), t275.buffer); + ulong length = le32_to_cpu(ent->t275.length); + ulong size = le32_to_cpu(ent->hdr.size); + void *buffer = ent->t275.buffer; - ql_dbg(ql_dbg_misc, vha, 0xd213, - "%s: buffer(%x) [%lx]\n", __func__, ent->t275.length, *len); - if (!ent->t275.length) { + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd213, + "%s: buffer(%lx) [%lx]\n", __func__, length, *len); + if (!length) { ql_dbg(ql_dbg_misc, vha, 0xd020, "%s: buffer zero length\n", __func__); qla27xx_skip_entry(ent, buf); goto done; } - if (offset + ent->t275.length > ent->hdr.size) { + if (offset + length > size) { + length = size - offset; ql_dbg(ql_dbg_misc, vha, 0xd030, - "%s: buffer overflow\n", __func__); - qla27xx_skip_entry(ent, buf); - goto done; + "%s: buffer overflow, truncate [%lx]\n", __func__, length); + ent->t275.length = cpu_to_le32(length); } - qla27xx_insertbuf(ent->t275.buffer, ent->t275.length, buf, len); + qla27xx_insertbuf(buffer, length, buf, len); done: return qla27xx_next_entry(ent); } @@ -790,15 +709,22 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t276(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - uint type = vha->hw->pdev->device >> 4 & 0xf; - uint func = vha->hw->port_no & 0x3; - ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd214, "%s: cond [%lx]\n", __func__, *len); - if (type != ent->t276.cond1 || func != ent->t276.cond2) { - ent = qla27xx_next_entry(ent); - qla27xx_skip_entry(ent, buf); + if (buf) { + ulong cond1 = le32_to_cpu(ent->t276.cond1); + ulong cond2 = le32_to_cpu(ent->t276.cond2); + uint type = vha->hw->pdev->device >> 4 & 0xf; + uint func = vha->hw->port_no & 0x3; + + if (type != cond1 || func != cond2) { + struct qla27xx_fwdt_template *tmp = buf; + + tmp->count--; + ent = qla27xx_next_entry(ent); + qla27xx_skip_entry(ent, buf); + } } return qla27xx_next_entry(ent); @@ -808,13 +734,15 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t277(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + ulong cmd_addr = le32_to_cpu(ent->t277.cmd_addr); + ulong wr_cmd_data = le32_to_cpu(ent->t277.wr_cmd_data); + ulong data_addr = le32_to_cpu(ent->t277.data_addr); ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd215, "%s: rdpep [%lx]\n", __func__, *len); - qla27xx_insert32(ent->t277.wr_cmd_data, buf, len); - qla27xx_write_reg(reg, ent->t277.cmd_addr, ent->t277.wr_cmd_data, buf); - qla27xx_read_reg(reg, ent->t277.data_addr, buf, len); + qla27xx_insert32(wr_cmd_data, buf, len); + qla27xx_write_reg(ISPREG(vha), cmd_addr, wr_cmd_data, buf); + qla27xx_read_reg(ISPREG(vha), data_addr, buf, len); return qla27xx_next_entry(ent); } @@ -823,12 +751,15 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t278(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { - struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + ulong cmd_addr = le32_to_cpu(ent->t278.cmd_addr); + ulong wr_cmd_data = le32_to_cpu(ent->t278.wr_cmd_data); + ulong data_addr = le32_to_cpu(ent->t278.data_addr); + ulong wr_data = le32_to_cpu(ent->t278.wr_data); ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd216, "%s: wrpep [%lx]\n", __func__, *len); - qla27xx_write_reg(reg, ent->t278.data_addr, ent->t278.wr_data, buf); - qla27xx_write_reg(reg, ent->t278.cmd_addr, ent->t278.wr_cmd_data, buf); + qla27xx_write_reg(ISPREG(vha), data_addr, wr_data, buf); + qla27xx_write_reg(ISPREG(vha), cmd_addr, wr_cmd_data, buf); return qla27xx_next_entry(ent); } @@ -837,8 +768,10 @@ static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_other(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { + ulong type = le32_to_cpu(ent->hdr.type); + ql_dbg(ql_dbg_misc, vha, 0xd2ff, - "%s: type %x [%lx]\n", __func__, ent->hdr.type, *len); + "%s: other %lx [%lx]\n", __func__, type, *len); qla27xx_skip_entry(ent, buf); return qla27xx_next_entry(ent); @@ -893,36 +826,27 @@ static void qla27xx_walk_template(struct scsi_qla_host *vha, struct qla27xx_fwdt_template *tmp, void *buf, ulong *len) { - struct qla27xx_fwdt_entry *ent = (void *)tmp + tmp->entry_offset; - ulong count = tmp->entry_count; + struct qla27xx_fwdt_entry *ent = (void *)tmp + + le32_to_cpu(tmp->entry_offset); + ulong type; + tmp->count = le32_to_cpu(tmp->entry_count); ql_dbg(ql_dbg_misc, vha, 0xd01a, - "%s: entry count %lx\n", __func__, count); - while (count--) { - ent = qla27xx_find_entry(ent->hdr.type)(vha, ent, buf, len); + "%s: entry count %u\n", __func__, tmp->count); + while (ent && tmp->count--) { + type = le32_to_cpu(ent->hdr.type); + ent = qla27xx_find_entry(type)(vha, ent, buf, len); if (!ent) break; } - if (count) + if (tmp->count) ql_dbg(ql_dbg_misc, vha, 0xd018, - "%s: entry residual count (%lx)\n", __func__, count); + "%s: entry count residual=+%u\n", __func__, tmp->count); if (ent) ql_dbg(ql_dbg_misc, vha, 0xd019, - "%s: missing end entry (%lx)\n", __func__, count); - - if (buf && *len != vha->hw->fw_dump_len) - ql_dbg(ql_dbg_misc, vha, 0xd01b, - "%s: length=%#lx residual=%+ld\n", - __func__, *len, vha->hw->fw_dump_len - *len); - - if (buf) { - ql_log(ql_log_warn, vha, 0xd015, - "Firmware dump saved to temp buffer (%lu/%p)\n", - vha->host_no, vha->hw->fw_dump); - qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); - } + "%s: missing end entry\n", __func__); } static void @@ -945,8 +869,8 @@ qla27xx_driver_info(struct qla27xx_fwdt_template *tmp) } static void -qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp, - struct scsi_qla_host *vha) +qla27xx_firmware_info(struct scsi_qla_host *vha, + struct qla27xx_fwdt_template *tmp) { tmp->firmware_version[0] = vha->hw->fw_major_version; tmp->firmware_version[1] = vha->hw->fw_minor_version; @@ -963,19 +887,19 @@ ql27xx_edit_template(struct scsi_qla_host *vha, { qla27xx_time_stamp(tmp); qla27xx_driver_info(tmp); - qla27xx_firmware_info(tmp, vha); + qla27xx_firmware_info(vha, tmp); } static inline uint32_t qla27xx_template_checksum(void *p, ulong size) { - uint32_t *buf = p; + __le32 *buf = p; uint64_t sum = 0; size /= sizeof(*buf); - while (size--) - sum += *buf++; + for ( ; size--; buf++) + sum += le32_to_cpu(*buf); sum = (sum & 0xffffffff) + (sum >> 32); @@ -991,29 +915,29 @@ qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp) static inline int qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp) { - return tmp->template_type == TEMPLATE_TYPE_FWDUMP; + return le32_to_cpu(tmp->template_type) == TEMPLATE_TYPE_FWDUMP; } -static void -qla27xx_execute_fwdt_template(struct scsi_qla_host *vha) +static ulong +qla27xx_execute_fwdt_template(struct scsi_qla_host *vha, + struct qla27xx_fwdt_template *tmp, void *buf) { - struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template; - ulong len; + ulong len = 0; if (qla27xx_fwdt_template_valid(tmp)) { len = tmp->template_size; - tmp = memcpy(vha->hw->fw_dump, tmp, len); + tmp = memcpy(buf, tmp, len); ql27xx_edit_template(vha, tmp); - qla27xx_walk_template(vha, tmp, tmp, &len); - vha->hw->fw_dump_len = len; - vha->hw->fw_dumped = 1; + qla27xx_walk_template(vha, tmp, buf, &len); } + + return len; } ulong -qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha) +qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha, void *p) { - struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template; + struct qla27xx_fwdt_template *tmp = p; ulong len = 0; if (qla27xx_fwdt_template_valid(tmp)) { @@ -1032,18 +956,6 @@ qla27xx_fwdt_template_size(void *p) return tmp->template_size; } -ulong -qla27xx_fwdt_template_default_size(void) -{ - return sizeof(ql27xx_fwdt_default_template); -} - -const void * -qla27xx_fwdt_template_default(void) -{ - return ql27xx_fwdt_default_template; -} - int qla27xx_fwdt_template_valid(void *p) { @@ -1051,7 +963,8 @@ qla27xx_fwdt_template_valid(void *p) if (!qla27xx_verify_template_header(tmp)) { ql_log(ql_log_warn, NULL, 0xd01c, - "%s: template type %x\n", __func__, tmp->template_type); + "%s: template type %x\n", __func__, + le32_to_cpu(tmp->template_type)); return false; } @@ -1074,17 +987,41 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) spin_lock_irqsave(&vha->hw->hardware_lock, flags); #endif - if (!vha->hw->fw_dump) - ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n"); - else if (!vha->hw->fw_dump_template) - ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n"); - else if (vha->hw->fw_dumped) - ql_log(ql_log_warn, vha, 0xd300, - "Firmware has been previously dumped (%p)," - " -- ignoring request\n", vha->hw->fw_dump); - else { - QLA_FW_STOPPED(vha->hw); - qla27xx_execute_fwdt_template(vha); + if (!vha->hw->fw_dump) { + ql_log(ql_log_warn, vha, 0xd01e, "-> fwdump no buffer\n"); + } else if (vha->hw->fw_dumped) { + ql_log(ql_log_warn, vha, 0xd01f, + "-> Firmware already dumped (%p) -- ignoring request\n", + vha->hw->fw_dump); + } else { + struct fwdt *fwdt = vha->hw->fwdt; + uint j; + ulong len; + void *buf = vha->hw->fw_dump; + + for (j = 0; j < 2; j++, fwdt++, buf += len) { + ql_log(ql_log_warn, vha, 0xd011, + "-> fwdt%u running...\n", j); + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0xd012, + "-> fwdt%u no template\n", j); + break; + } + len = qla27xx_execute_fwdt_template(vha, + fwdt->template, buf); + if (len != fwdt->dump_size) { + ql_log(ql_log_warn, vha, 0xd013, + "-> fwdt%u fwdump residual=%+ld\n", + j, fwdt->dump_size - len); + } + } + vha->hw->fw_dump_len = buf - (void *)vha->hw->fw_dump; + vha->hw->fw_dumped = 1; + + ql_log(ql_log_warn, vha, 0xd015, + "-> Firmware dump saved to buffer (%lu/%p) <%lx>\n", + vha->host_no, vha->hw->fw_dump, vha->hw->fw_dump_cap_flags); + qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); } #ifndef __CHECKER__ diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h index 5c2c2a8a19c4..d2a0014e8b21 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.h +++ b/drivers/scsi/qla2xxx/qla_tmpl.h @@ -11,12 +11,12 @@ #define IOBASE_ADDR offsetof(struct device_reg_24xx, iobase_addr) struct __packed qla27xx_fwdt_template { - uint32_t template_type; - uint32_t entry_offset; + __le32 template_type; + __le32 entry_offset; uint32_t template_size; - uint32_t reserved_1; + uint32_t count; /* borrow field for running/residual count */ - uint32_t entry_count; + __le32 entry_count; uint32_t template_version; uint32_t capture_timestamp; uint32_t template_checksum; @@ -65,8 +65,8 @@ struct __packed qla27xx_fwdt_template { struct __packed qla27xx_fwdt_entry { struct __packed { - uint32_t type; - uint32_t size; + __le32 type; + __le32 size; uint32_t reserved_1; uint8_t capture_flags; @@ -81,36 +81,36 @@ struct __packed qla27xx_fwdt_entry { } t255; struct __packed { - uint32_t base_addr; + __le32 base_addr; uint8_t reg_width; - uint16_t reg_count; + __le16 reg_count; uint8_t pci_offset; } t256; struct __packed { - uint32_t base_addr; - uint32_t write_data; + __le32 base_addr; + __le32 write_data; uint8_t pci_offset; uint8_t reserved[3]; } t257; struct __packed { - uint32_t base_addr; + __le32 base_addr; uint8_t reg_width; - uint16_t reg_count; + __le16 reg_count; uint8_t pci_offset; uint8_t banksel_offset; uint8_t reserved[3]; - uint32_t bank; + __le32 bank; } t258; struct __packed { - uint32_t base_addr; - uint32_t write_data; + __le32 base_addr; + __le32 write_data; uint8_t reserved[2]; uint8_t pci_offset; uint8_t banksel_offset; - uint32_t bank; + __le32 bank; } t259; struct __packed { @@ -121,14 +121,14 @@ struct __packed qla27xx_fwdt_entry { struct __packed { uint8_t pci_offset; uint8_t reserved[3]; - uint32_t write_data; + __le32 write_data; } t261; struct __packed { uint8_t ram_area; uint8_t reserved[3]; - uint32_t start_addr; - uint32_t end_addr; + __le32 start_addr; + __le32 end_addr; } t262; struct __packed { @@ -158,7 +158,7 @@ struct __packed qla27xx_fwdt_entry { struct __packed { uint8_t pci_offset; uint8_t reserved[3]; - uint32_t data; + __le32 data; } t267; struct __packed { @@ -173,23 +173,23 @@ struct __packed qla27xx_fwdt_entry { } t269; struct __packed { - uint32_t addr; - uint32_t count; + __le32 addr; + __le32 count; } t270; struct __packed { - uint32_t addr; - uint32_t data; + __le32 addr; + __le32 data; } t271; struct __packed { - uint32_t addr; - uint32_t count; + __le32 addr; + __le32 count; } t272; struct __packed { - uint32_t addr; - uint32_t count; + __le32 addr; + __le32 count; } t273; struct __packed { @@ -199,26 +199,26 @@ struct __packed qla27xx_fwdt_entry { } t274; struct __packed { - uint32_t length; + __le32 length; uint8_t buffer[]; } t275; struct __packed { - uint32_t cond1; - uint32_t cond2; + __le32 cond1; + __le32 cond2; } t276; struct __packed { - uint32_t cmd_addr; - uint32_t wr_cmd_data; - uint32_t data_addr; + __le32 cmd_addr; + __le32 wr_cmd_data; + __le32 data_addr; } t277; struct __packed { - uint32_t cmd_addr; - uint32_t wr_cmd_data; - uint32_t data_addr; - uint32_t wr_data; + __le32 cmd_addr; + __le32 wr_cmd_data; + __le32 data_addr; + __le32 wr_data; } t278; }; }; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 0690dac24081..cd6bdf71e533 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.00.00.14-k" +#define QLA2XXX_VERSION "10.01.00.16-k" #define QLA_DRIVER_MAJOR_VER 10 -#define QLA_DRIVER_MINOR_VER 0 +#define QLA_DRIVER_MINOR_VER 1 #define QLA_DRIVER_PATCH_VER 0 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 8a3075d17c63..d15412d3d9bd 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * This file contains tcm implementation using v4 configfs fabric infrastructure * for QLogic target mode HBAs @@ -11,35 +12,20 @@ * * Copyright (c) 2010 Cisco Systems, Inc * - * 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. ****************************************************************************/ #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/utsname.h> #include <linux/vmalloc.h> -#include <linux/init.h> #include <linux/list.h> #include <linux/slab.h> -#include <linux/kthread.h> #include <linux/types.h> #include <linux/string.h> #include <linux/configfs.h> #include <linux/ctype.h> #include <asm/unaligned.h> -#include <scsi/scsi.h> #include <scsi/scsi_host.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> @@ -267,25 +253,17 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) static void tcm_qla2xxx_complete_free(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - bool released = false; - unsigned long flags; cmd->cmd_in_wq = 0; WARN_ON(cmd->trc_flags & TRC_CMD_FREE); - spin_lock_irqsave(&cmd->cmd_lock, flags); + /* To do: protect all tgt_counters manipulations with proper locking. */ cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++; cmd->trc_flags |= TRC_CMD_FREE; cmd->cmd_sent_to_fw = 0; - if (cmd->released) - released = true; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - if (released) - qlt_free_cmd(cmd); - else - transport_generic_free_cmd(&cmd->se_cmd, 0); + transport_generic_free_cmd(&cmd->se_cmd, 0); } /* @@ -326,7 +304,6 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd) static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd) { struct qla_tgt_cmd *cmd; - unsigned long flags; if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) { struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd, @@ -336,14 +313,10 @@ static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd) } cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - spin_lock_irqsave(&cmd->cmd_lock, flags); - if (cmd->cmd_sent_to_fw) { - cmd->released = 1; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - } else { - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - qlt_free_cmd(cmd); - } + if (WARN_ON(cmd->cmd_sent_to_fw)) + return; + + qlt_free_cmd(cmd); } static void tcm_qla2xxx_release_session(struct kref *kref) @@ -359,7 +332,6 @@ static void tcm_qla2xxx_put_sess(struct fc_port *sess) if (!sess) return; - assert_spin_locked(&sess->vha->hw->tgt.sess_lock); kref_put(&sess->sess_kref, tcm_qla2xxx_release_session); } @@ -374,8 +346,9 @@ static void tcm_qla2xxx_close_session(struct se_session *se_sess) spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); target_sess_cmd_list_set_waiting(se_sess); - tcm_qla2xxx_put_sess(sess); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + + tcm_qla2xxx_put_sess(sess); } static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess) @@ -399,6 +372,8 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) cmd->se_cmd.transport_state, cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); + transport_generic_request_failure(&cmd->se_cmd, + TCM_CHECK_CONDITION_ABORT_CMD); return 0; } cmd->trc_flags |= TRC_XFR_RDY; @@ -488,32 +463,18 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, static void tcm_qla2xxx_handle_data_work(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - unsigned long flags; /* * Ensure that the complete FCP WRITE payload has been received. * Otherwise return an exception via CHECK_CONDITION status. */ cmd->cmd_in_wq = 0; - - spin_lock_irqsave(&cmd->cmd_lock, flags); cmd->cmd_sent_to_fw = 0; - - if (cmd->released) { - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - qlt_free_cmd(cmd); - return; - } - - cmd->data_work = 1; if (cmd->aborted) { - cmd->data_work_free = 1; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - - tcm_qla2xxx_free_cmd(cmd); + transport_generic_request_failure(&cmd->se_cmd, + TCM_CHECK_CONDITION_ABORT_CMD); return; } - spin_unlock_irqrestore(&cmd->cmd_lock, flags); cmd->qpair->tgt_counters.qla_core_ret_ctio++; if (!cmd->write_data_transferred) { @@ -829,7 +790,6 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct fc_port *sess) static void tcm_qla2xxx_shutdown_sess(struct fc_port *sess) { - assert_spin_locked(&sess->vha->hw->tgt.sess_lock); target_sess_cmd_list_set_waiting(sess->se_sess); } @@ -1489,7 +1449,7 @@ static int tcm_qla2xxx_check_initiator_node_acl( */ tpg = lport->tpg_1; if (!tpg) { - pr_err("Unable to lcoate struct tcm_qla2xxx_lport->tpg_1\n"); + pr_err("Unable to locate struct tcm_qla2xxx_lport->tpg_1\n"); return -EINVAL; } /* diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig index e4dc7c733c29..4bdf31b1407a 100644 --- a/drivers/scsi/qla4xxx/Kconfig +++ b/drivers/scsi/qla4xxx/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SCSI_QLA_ISCSI tristate "QLogic ISP4XXX and ISP82XX host adapter family support" depends on PCI && SCSI && NET diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile index 4230977748cf..1f8a9096c744 100644 --- a/drivers/scsi/qla4xxx/Makefile +++ b/drivers/scsi/qla4xxx/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o ql4_83xx.o diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6e4f4931ae17..8c674eca09f1 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -5930,7 +5930,7 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) val = rd_nvram_byte(ha, sec_addr); if (val & BIT_7) ddb_index[1] = (val & 0x7f); - + goto exit_boot_info; } else if (is_qla80XX(ha)) { buf = dma_alloc_coherent(&ha->pdev->dev, size, &buf_dma, GFP_KERNEL); diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 8b471a925b43..136681ad18a5 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -139,7 +139,7 @@ static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int } else { /* out */ #if QL_TURBO_PDMA rtrc(4) - if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ + if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ outsl(qbase + 4, request, 32); reqlen -= 128; request += 128; @@ -240,7 +240,7 @@ static void ql_icmd(struct scsi_cmnd *cmd) outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); outb(qlcfg7, qbase + 7); outb(qlcfg6, qbase + 6); - /**/ outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg5, qbase + 5); /* select timer */ outb(qlcfg9 & 7, qbase + 9); /* prescaler */ /* outb(0x99, qbase + 5); */ outb(scmd_id(cmd), qbase + 4); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 0e22512bd3e4..9335849f6bea 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver. * * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net) diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 5c3d6e1e0145..898a0bdf8df6 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * raid_class.c - implementation of a simple raid visualisation class * * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com> * - * This file is licensed under GPLv2 - * * This class is designed to allow raid attributes to be visualised and * manipulated in a form independent of the underlying raid. Ultimately this * should work for both hardware and software raids. diff --git a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl index 7d651d99afcb..0300f4c5562e 100644 --- a/drivers/scsi/script_asm.pl +++ b/drivers/scsi/script_asm.pl @@ -1,4 +1,5 @@ #!/usr/bin/perl -s +# SPDX-License-Identifier: GPL-2.0-or-later # NCR 53c810 script assembler # Sponsored by @@ -13,20 +14,6 @@ # Support for 53c710 (via -ncr7x0_family switch) added by Richard # Hirst <richard@sleepie.demon.co.uk> - 15th March 1997 # -# 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 program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# # TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation. # diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 99a7b9f520ae..1f5b5c8a7f72 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * scsi.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale @@ -85,15 +86,10 @@ unsigned int scsi_logging_level; EXPORT_SYMBOL(scsi_logging_level); #endif -/* sd, scsi core and power management need to coordinate flushing async actions */ -ASYNC_DOMAIN(scsi_sd_probe_domain); -EXPORT_SYMBOL(scsi_sd_probe_domain); - /* - * Separate domain (from scsi_sd_probe_domain) to maximize the benefit of - * asynchronous system resume operations. It is marked 'exclusive' to avoid - * being included in the async_synchronize_full() that is invoked by - * dpm_resume() + * Domain for asynchronous system resume operations. It is marked 'exclusive' + * to avoid being included in the async_synchronize_full() that is invoked by + * dpm_resume(). */ ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain); EXPORT_SYMBOL(scsi_sd_pm_domain); @@ -820,7 +816,6 @@ static void __exit exit_scsi(void) scsi_exit_devinfo(); scsi_exit_procfs(); scsi_exit_queue(); - async_unregister_domain(&scsi_sd_probe_domain); } subsys_initcall(init_scsi); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 2740a90501a0..d323523f5f9d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv * Copyright (C) 1992 Eric Youngdale @@ -8,13 +9,7 @@ * * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * * For documentation see http://sg.danny.cz/sg/sdebug26.html - * */ diff --git a/drivers/scsi/scsi_debugfs.h b/drivers/scsi/scsi_debugfs.h index 951b043e82d0..d125d1bd4184 100644 --- a/drivers/scsi/scsi_debugfs.h +++ b/drivers/scsi/scsi_debugfs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ struct request; struct seq_file; diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index c14006ac98f9..42f0550d6b11 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * SCSI device handler infrastruture. * - * 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 program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * Copyright IBM Corporation, 2007 * Authors: * Chandra Seetharaman <sekharan@us.ibm.com> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1b8378f36139..1c470e31ae81 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * scsi_error.c Copyright (C) 1997 Eric Youngdale * @@ -1054,7 +1055,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, struct scsi_device *sdev = scmd->device; struct Scsi_Host *shost = sdev->host; DECLARE_COMPLETION_ONSTACK(done); - unsigned long timeleft = timeout; + unsigned long timeleft = timeout, delay; struct scsi_eh_save ses; const unsigned long stall_for = msecs_to_jiffies(100); int rtn; @@ -1065,7 +1066,29 @@ retry: scsi_log_send(scmd); scmd->scsi_done = scsi_eh_done; - rtn = shost->hostt->queuecommand(shost, scmd); + + /* + * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can + * change the SCSI device state after we have examined it and before + * .queuecommand() is called. + */ + mutex_lock(&sdev->state_mutex); + while (sdev->sdev_state == SDEV_BLOCK && timeleft > 0) { + mutex_unlock(&sdev->state_mutex); + SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_DEBUG, sdev, + "%s: state %d <> %d\n", __func__, sdev->sdev_state, + SDEV_BLOCK)); + delay = min(timeleft, stall_for); + timeleft -= delay; + msleep(jiffies_to_msecs(delay)); + mutex_lock(&sdev->state_mutex); + } + if (sdev->sdev_state != SDEV_BLOCK) + rtn = shost->hostt->queuecommand(shost, scmd); + else + rtn = SCSI_MLQUEUE_DEVICE_BUSY; + mutex_unlock(&sdev->state_mutex); + if (rtn) { if (timeleft > stall_for) { scsi_eh_restore_cmnd(scmd, &ses); @@ -2393,7 +2416,6 @@ out_put_autopm_host: scsi_autopm_put_host(shost); return error; } -EXPORT_SYMBOL(scsi_ioctl_reset); bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd, struct scsi_sense_hdr *sshdr) diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 840d96fe81bc..57bcd05605bf 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Changes: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 08/23/2000 diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 07dfc17d4824..e1da8c70a266 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 1999 Eric Youngdale * Copyright (C) 2014 Christoph Hellwig @@ -39,6 +40,18 @@ #include "scsi_priv.h" #include "scsi_logging.h" +/* + * Size of integrity metadata is usually small, 1 inline sg should + * cover normal cases. + */ +#ifdef CONFIG_ARCH_NO_SG_CHAIN +#define SCSI_INLINE_PROT_SG_CNT 0 +#define SCSI_INLINE_SG_CNT 0 +#else +#define SCSI_INLINE_PROT_SG_CNT 1 +#define SCSI_INLINE_SG_CNT 2 +#endif + static struct kmem_cache *scsi_sdb_cache; static struct kmem_cache *scsi_sense_cache; static struct kmem_cache *scsi_sense_isadma_cache; @@ -141,8 +154,6 @@ scsi_set_blocked(struct scsi_cmnd *cmd, int reason) static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd) { - struct scsi_device *sdev = cmd->device; - if (cmd->request->rq_flags & RQF_DONTPREP) { cmd->request->rq_flags &= ~RQF_DONTPREP; scsi_mq_uninit_cmd(cmd); @@ -150,7 +161,6 @@ static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd) WARN_ON_ONCE(true); } blk_mq_requeue_request(cmd->request, true); - put_device(&sdev->sdev_gendev); } /** @@ -189,19 +199,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) */ cmd->result = 0; - /* - * 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); } /* @@ -556,9 +554,11 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd) static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd) { if (cmd->sdb.table.nents) - sg_free_table_chained(&cmd->sdb.table, true); + sg_free_table_chained(&cmd->sdb.table, + SCSI_INLINE_SG_CNT); if (scsi_prot_sg_count(cmd)) - sg_free_table_chained(&cmd->prot_sdb->table, true); + sg_free_table_chained(&cmd->prot_sdb->table, + SCSI_INLINE_PROT_SG_CNT); } static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd) @@ -619,7 +619,6 @@ static bool scsi_end_request(struct request *req, blk_status_t error, blk_mq_run_hw_queues(q, true); percpu_ref_put(&q->q_usage_counter); - put_device(&sdev->sdev_gendev); return false; } @@ -992,7 +991,8 @@ static blk_status_t scsi_init_sgtable(struct request *req, * If sg table allocation fails, requeue request later. */ if (unlikely(sg_alloc_table_chained(&sdb->table, - blk_rq_nr_phys_segments(req), sdb->table.sgl))) + blk_rq_nr_phys_segments(req), sdb->table.sgl, + SCSI_INLINE_SG_CNT))) return BLK_STS_RESOURCE; /* @@ -1046,7 +1046,8 @@ blk_status_t scsi_init_io(struct scsi_cmnd *cmd) ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio); if (sg_alloc_table_chained(&prot_sdb->table, ivecs, - prot_sdb->table.sgl)) { + prot_sdb->table.sgl, + SCSI_INLINE_PROT_SG_CNT)) { ret = BLK_STS_RESOURCE; goto out_free_sgtables; } @@ -1557,9 +1558,9 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) } /* Size in bytes of the sg-list stored in the scsi-mq command-private data. */ -static unsigned int scsi_mq_sgl_size(struct Scsi_Host *shost) +static unsigned int scsi_mq_inline_sgl_size(struct Scsi_Host *shost) { - return min_t(unsigned int, shost->sg_tablesize, SG_CHUNK_SIZE) * + return min_t(unsigned int, shost->sg_tablesize, SCSI_INLINE_SG_CNT) * sizeof(struct scatterlist); } @@ -1613,7 +1614,6 @@ static void scsi_mq_put_budget(struct blk_mq_hw_ctx *hctx) struct scsi_device *sdev = q->queuedata; atomic_dec(&sdev->device_busy); - put_device(&sdev->sdev_gendev); } static bool scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx) @@ -1621,16 +1621,9 @@ static bool scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx) struct request_queue *q = hctx->queue; struct scsi_device *sdev = q->queuedata; - if (!get_device(&sdev->sdev_gendev)) - goto out; - if (!scsi_dev_queue_ready(q, sdev)) - goto out_put_device; - - return true; + if (scsi_dev_queue_ready(q, sdev)) + return true; -out_put_device: - put_device(&sdev->sdev_gendev); -out: if (atomic_read(&sdev->device_busy) == 0 && !scsi_device_blocked(sdev)) blk_mq_delay_run_hw_queue(hctx, SCSI_QUEUE_DELAY); return false; @@ -1749,7 +1742,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, if (scsi_host_get_prot(shost)) { sg = (void *)cmd + sizeof(struct scsi_cmnd) + shost->hostt->cmd_size; - cmd->prot_sdb = (void *)sg + scsi_mq_sgl_size(shost); + cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost); } return 0; @@ -1770,7 +1763,7 @@ static int scsi_map_queues(struct blk_mq_tag_set *set) if (shost->hostt->map_queues) return shost->hostt->map_queues(shost); - return blk_mq_map_queues(&set->map[0]); + return blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]); } void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) @@ -1843,10 +1836,11 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost) { unsigned int cmd_size, sgl_size; - sgl_size = scsi_mq_sgl_size(shost); + sgl_size = scsi_mq_inline_sgl_size(shost); cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size; if (scsi_host_get_prot(shost)) - cmd_size += sizeof(struct scsi_data_buffer) + sgl_size; + cmd_size += sizeof(struct scsi_data_buffer) + + sizeof(struct scatterlist) * SCSI_INLINE_PROT_SG_CNT; memset(&shost->tag_set, 0, sizeof(shost->tag_set)); shost->tag_set.ops = &scsi_mq_ops; @@ -2639,10 +2633,6 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait); * a legal transition). When the device is in this state, command processing * is paused until the device leaves the SDEV_BLOCK state. See also * scsi_internal_device_unblock(). - * - * To do: avoid that scsi_send_eh_cmnd() calls queuecommand() after - * scsi_internal_device_block() has blocked a SCSI device and also - * remove the rport mutex lock and unlock calls from srp_queuecommand(). */ static int scsi_internal_device_block(struct scsi_device *sdev) { diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index bd70339c1242..39b8cc4574b4 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * scsi_logging.c * * Copyright (C) 2014 SUSE Linux Products GmbH * Copyright (C) 2014 Hannes Reinecke <hare@suse.de> - * - * This file is released under the GPLv2 */ #include <linux/kernel.h> diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 50e624fb8307..d7f76fd84256 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * scsi_netlink.c - SCSI Transport Netlink Interface * * Copyright (C) 2006 James Smart, Emulex Corporation - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/time.h> #include <linux/jiffies.h> diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 7639df91b110..74ded5f3c236 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * scsi_pm.c Copyright (C) 2010 Alan Stern * @@ -175,11 +176,7 @@ static int scsi_bus_resume_common(struct device *dev, static int scsi_bus_prepare(struct device *dev) { - if (scsi_is_sdev_device(dev)) { - /* sd probing uses async_schedule. Wait until it finishes. */ - async_synchronize_full_domain(&scsi_sd_probe_domain); - - } else if (scsi_is_host_device(dev)) { + if (scsi_is_host_device(dev)) { /* Wait until async scanning is finished */ scsi_complete_async_scans(); } diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 5f21547b2ad2..cc2859d76d81 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -175,7 +175,6 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} #endif /* CONFIG_PM */ extern struct async_domain scsi_sd_pm_domain; -extern struct async_domain scsi_sd_probe_domain; /* scsi_dh.c */ #ifdef CONFIG_SCSI_DH diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 7f0ceb65c3f3..c074631086a4 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } -static int always_match(struct device *dev, void *data) +static int always_match(struct device *dev, const void *data) { return 1; } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 53380e07b40e..058079f915f1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1129,7 +1129,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, * that no LUN is present, so don't add sdev in these cases. * Two specific examples are: * 1) NetApp targets: return PQ=1, PDT=0x1f - * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" + * 2) IBM/2145 targets: return PQ=1, PDT=0 + * 3) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" * in the UFI 1.0 spec (we cannot rely on reserved bits). * * References: @@ -1143,8 +1144,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, * PDT=00h Direct-access device (floppy) * PDT=1Fh none (no FDD connected to the requested logical unit) */ - if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) && - (result[0] & 0x1f) == 0x1f && + if (((result[0] >> 5) == 1 || + (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f)) && !scsi_is_wlun(lun)) { SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, "scsi scan: peripheral device type" diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c index 546f16299ef9..7259704a7f52 100644 --- a/drivers/scsi/scsi_sysctl.c +++ b/drivers/scsi/scsi_sysctl.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2003 Christoph Hellwig. - * Released under GPL v2. */ #include <linux/errno.h> diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 3b119ca0cc0c..64c96c7828ee 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * scsi_sysfs.c * @@ -766,8 +767,13 @@ store_state_field(struct device *dev, struct device_attribute *attr, break; } } - if (!state) + switch (state) { + case SDEV_RUNNING: + case SDEV_OFFLINE: + break; + default: return -EINVAL; + } mutex_lock(&sdev->state_mutex); ret = scsi_device_set_state(sdev, state); diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 0ff083bbf5b1..0f17e7dac1b0 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 FUJITSU LIMITED * Copyright (C) 2010 Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/trace_seq.h> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index d7035270d274..2732fa65119c 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1,29 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * FiberChannel transport specific attributes exported to sysfs. * * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ======== - * * Copyright (C) 2004-2007 James Smart, Emulex Corporation * Rewrite for host, target, device, and remote port attributes, * statistics, and service functions... * Add vports, etc - * */ #include <linux/module.h> #include <linux/init.h> @@ -147,6 +130,7 @@ static const struct { { FCH_EVT_PORT_OFFLINE, "port_offline" }, { FCH_EVT_PORT_FABRIC, "port_fabric" }, { FCH_EVT_LINK_UNKNOWN, "link_unknown" }, + { FCH_EVT_LINK_FPIN, "link_FPIN" }, { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" }, }; fc_enum_name_search(host_event_code, fc_host_event_code, @@ -295,6 +279,9 @@ static const struct { { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, { FC_PORT_ROLE_IP_PORT, "IP Port" }, { FC_PORT_ROLE_FCP_DUMMY_INITIATOR, "FCP Dummy Initiator" }, + { FC_PORT_ROLE_NVME_INITIATOR, "NVMe Initiator" }, + { FC_PORT_ROLE_NVME_TARGET, "NVMe Target" }, + { FC_PORT_ROLE_NVME_DISCOVERY, "NVMe Discovery" }, }; fc_bitfield_name_search(port_roles, fc_port_role_names) @@ -523,20 +510,23 @@ fc_get_event_number(void) } EXPORT_SYMBOL(fc_get_event_number); - /** - * fc_host_post_event - called to post an even on an fc_host. + * fc_host_post_fc_event - routine to do the work of posting an event + * on an fc_host. * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @event_code: fc_host event being posted - * @event_data: 32bits of data for the event being posted + * @data_len: amount, in bytes, of event data + * @data_buf: pointer to event data + * @vendor_id: value for Vendor id * * Notes: * This routine assumes no locks are held on entry. */ void -fc_host_post_event(struct Scsi_Host *shost, u32 event_number, - enum fc_host_event_code event_code, u32 event_data) +fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number, + enum fc_host_event_code event_code, + u32 data_len, char *data_buf, u64 vendor_id) { struct sk_buff *skb; struct nlmsghdr *nlh; @@ -545,12 +535,15 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number, u32 len; int err; + if (!data_buf || data_len < 4) + data_len = 0; + if (!scsi_nl_sock) { err = -ENOENT; goto send_fail; } - len = FC_NL_MSGALIGN(sizeof(*event)); + len = FC_NL_MSGALIGN(sizeof(*event) + data_len); skb = nlmsg_new(len, GFP_KERNEL); if (!skb) { @@ -568,12 +561,13 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number, INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, FC_NL_ASYNC_EVENT, len); event->seconds = ktime_get_real_seconds(); - event->vendor_id = 0; + event->vendor_id = vendor_id; event->host_no = shost->host_no; - event->event_datalen = sizeof(u32); /* bytes */ + event->event_datalen = data_len; /* bytes */ event->event_num = event_number; event->event_code = event_code; - event->event_data = event_data; + if (data_len) + memcpy(&event->event_data, data_buf, data_len); nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, GFP_KERNEL); @@ -586,14 +580,35 @@ send_fail: printk(KERN_WARNING "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", __func__, shost->host_no, - (name) ? name : "<unknown>", event_data, err); + (name) ? name : "<unknown>", + (data_len) ? *((u32 *)data_buf) : 0xFFFFFFFF, err); return; } +EXPORT_SYMBOL(fc_host_post_fc_event); + +/** + * fc_host_post_event - called to post an even on an fc_host. + * @shost: host the event occurred on + * @event_number: fc event number obtained from get_fc_event_number() + * @event_code: fc_host event being posted + * @event_data: 32bits of data for the event being posted + * + * Notes: + * This routine assumes no locks are held on entry. + */ +void +fc_host_post_event(struct Scsi_Host *shost, u32 event_number, + enum fc_host_event_code event_code, u32 event_data) +{ + fc_host_post_fc_event(shost, event_number, event_code, + (u32)sizeof(u32), (char *)&event_data, 0); +} EXPORT_SYMBOL(fc_host_post_event); /** - * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host + * fc_host_post_vendor_event - called to post a vendor unique event + * on an fc_host * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @data_len: amount, in bytes, of vendor unique data @@ -607,56 +622,27 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, u32 data_len, char * data_buf, u64 vendor_id) { - struct sk_buff *skb; - struct nlmsghdr *nlh; - struct fc_nl_event *event; - u32 len; - int err; - - if (!scsi_nl_sock) { - err = -ENOENT; - goto send_vendor_fail; - } - - len = FC_NL_MSGALIGN(sizeof(*event) + data_len); - - skb = nlmsg_new(len, GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - goto send_vendor_fail; - } - - nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0); - if (!nlh) { - err = -ENOBUFS; - goto send_vendor_fail_skb; - } - event = nlmsg_data(nlh); - - INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, - FC_NL_ASYNC_EVENT, len); - event->seconds = ktime_get_real_seconds(); - event->vendor_id = vendor_id; - event->host_no = shost->host_no; - event->event_datalen = data_len; /* bytes */ - event->event_num = event_number; - event->event_code = FCH_EVT_VENDOR_UNIQUE; - memcpy(&event->event_data, data_buf, data_len); - - nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, - GFP_KERNEL); - return; - -send_vendor_fail_skb: - kfree_skb(skb); -send_vendor_fail: - printk(KERN_WARNING - "%s: Dropped Event : host %d vendor_unique - err %d\n", - __func__, shost->host_no, err); - return; + fc_host_post_fc_event(shost, event_number, FCH_EVT_VENDOR_UNIQUE, + data_len, data_buf, vendor_id); } EXPORT_SYMBOL(fc_host_post_vendor_event); +/** + * fc_host_rcv_fpin - routine to process a received FPIN. + * @shost: host the FPIN was received on + * @fpin_len: length of FPIN payload, in bytes + * @fpin_buf: pointer to FPIN payload + * + * Notes: + * This routine assumes no locks are held on entry. + */ +void +fc_host_fpin_rcv(struct Scsi_Host *shost, u32 fpin_len, char *fpin_buf) +{ + fc_host_post_fc_event(shost, fc_get_event_number(), + FCH_EVT_LINK_FPIN, fpin_len, fpin_buf, 0); +} +EXPORT_SYMBOL(fc_host_fpin_rcv); static __init int fc_transport_init(void) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 0a82e93566dc..417b868d8735 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * iSCSI transport class definitions * @@ -5,20 +6,6 @@ * Copyright (C) Mike Christie, 2004 - 2005 * Copyright (C) Dmitry Yusupov, 2004 - 2005 * Copyright (C) Alex Aizman, 2004 - 2005 - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/module.h> #include <linux/mutex.h> diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 60f1a81d2034..ef138c57e2a6 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005-2006 Dell Inc. - * Released under GPL v2. * * Serial Attached SCSI (SAS) transport class. * diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 40b85b752b79..f8661062ef95 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Parallel SCSI (SPI) transport specific attributes exported to sysfs. * * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. * Copyright (c) 2004, 2005 James Bottomley <James.Bottomley@SteelEye.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/ctype.h> #include <linux/init.h> diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 4e46fdb2d7c9..d4d1104fac99 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI RDMA (SRP) transport class * * Copyright (C) 2007 FUJITA Tomonori <tomof@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, version 2 of the - * License. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include <linux/init.h> #include <linux/module.h> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2b2bc4b49d78..149d406aacc9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sd.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale @@ -567,6 +568,7 @@ static struct scsi_driver sd_template = { .name = "sd", .owner = THIS_MODULE, .probe = sd_probe, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .remove = sd_remove, .shutdown = sd_shutdown, .pm = &sd_pm_ops, @@ -2256,22 +2258,6 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, #define READ_CAPACITY_RETRIES_ON_RESET 10 -/* - * Ensure that we don't overflow sector_t when CONFIG_LBDAF is not set - * and the reported logical block size is bigger than 512 bytes. Note - * that last_sector is a u64 and therefore logical_to_sectors() is not - * applicable. - */ -static bool sd_addressable_capacity(u64 lba, unsigned int sector_size) -{ - u64 last_sector = (lba + 1ULL) << (ilog2(sector_size) - 9); - - if (sizeof(sector_t) == 4 && last_sector > U32_MAX) - return false; - - return true; -} - static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, unsigned char *buffer) { @@ -2337,14 +2323,6 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, return -ENODEV; } - if (!sd_addressable_capacity(lba, sector_size)) { - sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " - "kernel compiled with support for large block " - "devices.\n"); - sdkp->capacity = 0; - return -EOVERFLOW; - } - /* Logical blocks per physical block exponent */ sdkp->physical_block_size = (1 << (buffer[13] & 0xf)) * sector_size; @@ -2426,14 +2404,6 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, return sector_size; } - if (!sd_addressable_capacity(lba, sector_size)) { - sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " - "kernel compiled with support for large block " - "devices.\n"); - sdkp->capacity = 0; - return -EOVERFLOW; - } - sdkp->capacity = lba + 1; sdkp->physical_block_size = sector_size; return sector_size; @@ -2603,7 +2573,6 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) int res; struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; - int disk_ro = get_disk_ro(sdkp->disk); int old_wp = sdkp->write_prot; set_disk_ro(sdkp->disk, 0); @@ -2644,7 +2613,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) "Test WP failed, assume Write Enabled\n"); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); - set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro); + set_disk_ro(sdkp->disk, sdkp->write_prot); if (sdkp->first_scan || old_wp != sdkp->write_prot) { sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", sdkp->write_prot ? "on" : "off"); @@ -3284,68 +3253,6 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) return 0; } -/* - * The asynchronous part of sd_probe - */ -static void sd_probe_async(void *data, async_cookie_t cookie) -{ - struct scsi_disk *sdkp = data; - struct scsi_device *sdp; - struct gendisk *gd; - u32 index; - struct device *dev; - - sdp = sdkp->device; - gd = sdkp->disk; - index = sdkp->index; - dev = &sdp->sdev_gendev; - - gd->major = sd_major((index & 0xf0) >> 4); - gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); - - gd->fops = &sd_fops; - gd->private_data = &sdkp->driver; - gd->queue = sdkp->device->request_queue; - - /* defaults, until the device tells us otherwise */ - sdp->sector_size = 512; - sdkp->capacity = 0; - sdkp->media_present = 1; - sdkp->write_prot = 0; - sdkp->cache_override = 0; - sdkp->WCE = 0; - sdkp->RCD = 0; - sdkp->ATO = 0; - sdkp->first_scan = 1; - sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; - - sd_revalidate_disk(gd); - - gd->flags = GENHD_FL_EXT_DEVT; - if (sdp->removable) { - gd->flags |= GENHD_FL_REMOVABLE; - gd->events |= DISK_EVENT_MEDIA_CHANGE; - } - - blk_pm_runtime_init(sdp->request_queue, dev); - device_add_disk(dev, gd, NULL); - if (sdkp->capacity) - sd_dif_config_host(sdkp); - - sd_revalidate_disk(gd); - - if (sdkp->security) { - sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit); - if (sdkp->opal_dev) - sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n"); - } - - sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", - sdp->removable ? "removable " : ""); - scsi_autopm_put_device(sdp); - put_device(&sdkp->dev); -} - /** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once @@ -3435,8 +3342,50 @@ static int sd_probe(struct device *dev) get_device(dev); dev_set_drvdata(dev, sdkp); - get_device(&sdkp->dev); /* prevent release before async_schedule */ - async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain); + gd->major = sd_major((index & 0xf0) >> 4); + gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); + + gd->fops = &sd_fops; + gd->private_data = &sdkp->driver; + gd->queue = sdkp->device->request_queue; + + /* defaults, until the device tells us otherwise */ + sdp->sector_size = 512; + sdkp->capacity = 0; + sdkp->media_present = 1; + sdkp->write_prot = 0; + sdkp->cache_override = 0; + sdkp->WCE = 0; + sdkp->RCD = 0; + sdkp->ATO = 0; + sdkp->first_scan = 1; + sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; + + sd_revalidate_disk(gd); + + gd->flags = GENHD_FL_EXT_DEVT; + if (sdp->removable) { + gd->flags |= GENHD_FL_REMOVABLE; + gd->events |= DISK_EVENT_MEDIA_CHANGE; + gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT; + } + + blk_pm_runtime_init(sdp->request_queue, dev); + device_add_disk(dev, gd, NULL); + if (sdkp->capacity) + sd_dif_config_host(sdkp); + + sd_revalidate_disk(gd); + + if (sdkp->security) { + sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit); + if (sdkp->opal_dev) + sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n"); + } + + sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", + sdp->removable ? "removable " : ""); + scsi_autopm_put_device(sdp); return 0; @@ -3472,7 +3421,6 @@ static int sd_remove(struct device *dev) scsi_autopm_get_device(sdkp->device); async_synchronize_full_domain(&scsi_sd_pm_domain); - async_synchronize_full_domain(&scsi_sd_probe_domain); device_del(&sdkp->dev); del_gendisk(sdkp->disk); sd_shutdown(dev); diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index db72c82486e3..4cadb26070a8 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sd_dif.c - SCSI Data Integrity Field * * Copyright (C) 2007, 2008 Oracle Corporation * Written by: Martin K. Petersen <martin.petersen@oracle.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * */ #include <linux/blkdev.h> diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index a340af797a85..7334024b64f1 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI Zoned Block commands * @@ -5,21 +6,6 @@ * Written by: Hannes Reinecke <hare@suse.de> * Modified by: Damien Le Moal <damien.lemoal@hgst.com> * Modified by: Shaun Tancheff <shaun.tancheff@seagate.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * */ #include <linux/blkdev.h> diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 0fc39224ce1e..c2afba2a5414 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCSI Enclosure Services * * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** 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. -** -**----------------------------------------------------------------------------- -*/ + */ #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d3f15319b9b3..cce757506383 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * History: * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), @@ -8,12 +9,6 @@ * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: * Copyright (C) 1998 - 2014 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * */ static int sg_version_num = 30536; /* 2 digits for each component */ diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 82ed99848378..22302612e032 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *---------------------------------------------------------------------------- * * MCA card detection code by Trent McNair. (now deleted) @@ -23,7 +11,6 @@ * Auto probing of EISA config space from Trevor Hemsley. * * Rewritten to use 53c700.c by James.Bottomley@SteelEye.com - * */ #include <linux/module.h> diff --git a/drivers/scsi/smartpqi/Makefile b/drivers/scsi/smartpqi/Makefile index a03a6edb0060..28985e508b5c 100644 --- a/drivers/scsi/smartpqi/Makefile +++ b/drivers/scsi/smartpqi/Makefile @@ -1,2 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SCSI_SMARTPQI) += smartpqi.o smartpqi-objs := smartpqi_init.o smartpqi_sis.o smartpqi_sas_transport.o diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index af962368818b..e8e768849c70 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -1,18 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * driver for Microsemi PQI-based storage controllers - * Copyright (c) 2016-2017 Microsemi Corporation + * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries + * Copyright (c) 2016-2018 Microsemi Corporation * Copyright (c) 2016 PMC-Sierra, Inc. * - * 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; version 2 of the License. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com + * Questions/Comments/Bugfixes to storagedev@microchip.com * */ diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 75ec43aa8df3..8fd5ffc55792 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -1,18 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * driver for Microsemi PQI-based storage controllers - * Copyright (c) 2016-2017 Microsemi Corporation + * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries + * Copyright (c) 2016-2018 Microsemi Corporation * Copyright (c) 2016 PMC-Sierra, Inc. * - * 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; version 2 of the License. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com + * Questions/Comments/Bugfixes to storagedev@microchip.com * */ @@ -40,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "1.2.4-070" +#define DRIVER_VERSION "1.2.6-015" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 2 -#define DRIVER_RELEASE 4 -#define DRIVER_REVISION 70 +#define DRIVER_RELEASE 6 +#define DRIVER_REVISION 15 #define DRIVER_NAME "Microsemi PQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" @@ -2762,16 +2755,25 @@ static void pqi_process_raid_io_error(struct pqi_io_request *io_request) scsi_normalize_sense(error_info->data, sense_data_length, &sshdr) && sshdr.sense_key == HARDWARE_ERROR && - sshdr.asc == 0x3e && - sshdr.ascq == 0x1) { + sshdr.asc == 0x3e) { struct pqi_ctrl_info *ctrl_info = shost_to_hba(scmd->device->host); struct pqi_scsi_dev *device = scmd->device->hostdata; - if (printk_ratelimit()) - scmd_printk(KERN_ERR, scmd, "received 'logical unit failure' from controller for scsi %d:%d:%d:%d\n", - ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun); - pqi_take_device_offline(scmd->device, "RAID"); - host_byte = DID_NO_CONNECT; + switch (sshdr.ascq) { + case 0x1: /* LOGICAL UNIT FAILURE */ + if (printk_ratelimit()) + scmd_printk(KERN_ERR, scmd, "received 'logical unit failure' from controller for scsi %d:%d:%d:%d\n", + ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun); + pqi_take_device_offline(scmd->device, "RAID"); + host_byte = DID_NO_CONNECT; + break; + + default: /* See http://www.t10.org/lists/asc-num.htm#ASC_3E */ + if (printk_ratelimit()) + scmd_printk(KERN_ERR, scmd, "received unhandled error %d from controller for scsi %d:%d:%d:%d\n", + sshdr.ascq, ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun); + break; + } } if (sense_data_length > SCSI_SENSE_BUFFERSIZE) @@ -4044,8 +4046,10 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info, return -ETIMEDOUT; msecs_blocked = jiffies_to_msecs(jiffies - start_jiffies); - if (msecs_blocked >= timeout_msecs) - return -ETIMEDOUT; + if (msecs_blocked >= timeout_msecs) { + rc = -ETIMEDOUT; + goto out; + } timeout_msecs -= msecs_blocked; } } @@ -5660,9 +5664,11 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info, return rc; } +/* Performs a reset at the LUN level. */ + #define PQI_LUN_RESET_RETRIES 3 #define PQI_LUN_RESET_RETRY_INTERVAL_MSECS 10000 -/* Performs a reset at the LUN level. */ +#define PQI_LUN_RESET_PENDING_IO_TIMEOUT_SECS 120 static int _pqi_device_reset(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device) @@ -5673,12 +5679,12 @@ static int _pqi_device_reset(struct pqi_ctrl_info *ctrl_info, for (retries = 0;;) { rc = pqi_lun_reset(ctrl_info, device); - if (rc != -EAGAIN || - ++retries > PQI_LUN_RESET_RETRIES) + if (rc != -EAGAIN || ++retries > PQI_LUN_RESET_RETRIES) break; msleep(PQI_LUN_RESET_RETRY_INTERVAL_MSECS); } - timeout_secs = rc ? PQI_LUN_RESET_TIMEOUT_SECS : NO_TIMEOUT; + + timeout_secs = rc ? PQI_LUN_RESET_PENDING_IO_TIMEOUT_SECS : NO_TIMEOUT; rc |= pqi_device_wait_for_pending_io(ctrl_info, device, timeout_secs); @@ -5707,6 +5713,7 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info, pqi_device_reset_done(device); mutex_unlock(&ctrl_info->lun_reset_mutex); + return rc; } @@ -5737,6 +5744,7 @@ static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd) pqi_wait_until_ofa_finished(ctrl_info); rc = pqi_device_reset(ctrl_info, device); + out: dev_err(&ctrl_info->pci_dev->dev, "reset of scsi %d:%d:%d:%d: %s\n", @@ -5795,7 +5803,7 @@ static int pqi_map_queues(struct Scsi_Host *shost) { struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost); - return blk_mq_pci_map_queues(&shost->tag_set.map[0], + return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT], ctrl_info->pci_dev, 0); } @@ -7285,7 +7293,7 @@ static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info) else mask = DMA_BIT_MASK(32); - rc = dma_set_mask(&ctrl_info->pci_dev->dev, mask); + rc = dma_set_mask_and_coherent(&ctrl_info->pci_dev->dev, mask); if (rc) { dev_err(&ctrl_info->pci_dev->dev, "failed to set DMA mask\n"); goto disable_device; @@ -7948,6 +7956,22 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x1104) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x1105) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x1106) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x193d, 0x1107) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x193d, 0x8460) }, { diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index 0e4ef215115f..5cca1b9ef1f1 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -1,18 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * driver for Microsemi PQI-based storage controllers - * Copyright (c) 2016-2017 Microsemi Corporation + * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries + * Copyright (c) 2016-2018 Microsemi Corporation * Copyright (c) 2016 PMC-Sierra, Inc. * - * 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; version 2 of the License. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com + * Questions/Comments/Bugfixes to storagedev@microchip.com * */ diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c index dcd11c6418cc..f0d6e88ba2c1 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.c +++ b/drivers/scsi/smartpqi/smartpqi_sis.c @@ -1,18 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * driver for Microsemi PQI-based storage controllers - * Copyright (c) 2016-2017 Microsemi Corporation + * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries + * Copyright (c) 2016-2018 Microsemi Corporation * Copyright (c) 2016 PMC-Sierra, Inc. * - * 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; version 2 of the License. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com + * Questions/Comments/Bugfixes to storagedev@microchip.com * */ diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h index d018cb9c3f82..86b0e484d921 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.h +++ b/drivers/scsi/smartpqi/smartpqi_sis.h @@ -1,18 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * driver for Microsemi PQI-based storage controllers - * Copyright (c) 2016-2017 Microsemi Corporation + * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries + * Copyright (c) 2016-2018 Microsemi Corporation * Copyright (c) 2016 PMC-Sierra, Inc. * - * 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; version 2 of the License. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com + * Questions/Comments/Bugfixes to storagedev@microchip.com * */ diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 1f9a087daf69..aef4881d8e21 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -*- mode: c; c-basic-offset: 8 -*- */ /* SNI RM driver @@ -5,19 +6,6 @@ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.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 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 program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** **----------------------------------------------------------------------------- */ diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 039c27c2d7b3..4664fdf75c0f 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sr.c Copyright (C) 1992 David Giller * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale @@ -716,6 +717,7 @@ static int sr_probe(struct device *dev) disk->fops = &sr_bdops; disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; + disk->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT; blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 19c022e66d63..e3266a64a477 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying file Documentation/scsi/st.txt for more information. @@ -227,7 +228,6 @@ static DEFINE_IDR(st_index_idr); -#include "osst_detect.h" #ifndef SIGS_FROM_OSST #define SIGS_FROM_OSST \ {"OnStream", "SC-", "", "osst"}, \ @@ -4266,9 +4266,10 @@ static int st_probe(struct device *dev) if (SDp->type != TYPE_TAPE) return -ENODEV; if ((stp = st_incompatible(SDp))) { - sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n"); sdev_printk(KERN_INFO, SDp, - "st: The suggested driver is %s.\n", stp); + "OnStream tapes are no longer supported;\n"); + sdev_printk(KERN_INFO, SDp, + "please mail to linux-scsi@vger.kernel.org.\n"); return -ENODEV; } @@ -4922,7 +4923,8 @@ static int sgl_map_user_pages(struct st_buffer *STbp, /* Try to fault in all of the necessary pages */ /* rw==READ means read from drive, write into memory area */ - res = get_user_pages_fast(uaddr, nr_pages, rw == READ, pages); + res = get_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0, + pages); /* Errors and no page mapped should return here */ if (res < nr_pages) diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index f6bef7ad65e7..33287b6bdf0e 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -1,16 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * SuperTrak EX Series Storage Controller driver for Linux * * Copyright (C) 2005-2015 Promise Technology Inc. * - * 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. - * * Written By: * Ed Lin <promise_linux@promise.com> - * */ #include <linux/init.h> diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 8472de1007ff..c2b6a0ca6933 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2009, Microsoft Corporation. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * * Authors: * Haiyang Zhang <haiyangz@microsoft.com> * Hank Janssen <hjanssen@microsoft.com> @@ -387,6 +375,7 @@ enum storvsc_request_type { static int storvsc_ringbuffer_size = (128 * 1024); static u32 max_outstanding_req_per_channel; +static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth); static int storvsc_vcpus_per_sub_channel = 4; @@ -1711,6 +1700,7 @@ static struct scsi_host_template scsi_driver = { .dma_boundary = PAGE_SIZE-1, .no_write_same = 1, .track_queue_depth = 1, + .change_queue_depth = storvsc_change_queue_depth, }; enum { @@ -1917,6 +1907,15 @@ err_out0: return ret; } +/* Change a scsi target's queue depth */ +static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth) +{ + if (queue_depth > scsi_driver.can_queue) + queue_depth = scsi_driver.can_queue; + + return scsi_change_queue_depth(sdev, queue_depth); +} + static int storvsc_remove(struct hv_device *dev) { struct storvsc_device *stor_device = hv_get_drvdata(dev); diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 95a7ea7eefa0..3d80ab67a626 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) * diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index c9a55d0f076d..440a73eae647 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* sun3x_esp.c: ESP front-end for Sun3x systems. * * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de) diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index c71bd01fef94..964130d2c8a6 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* sun_esp.c: ESP front-end for Sparc SBUS systems. * * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) diff --git a/drivers/scsi/sym53c8xx_2/Makefile b/drivers/scsi/sym53c8xx_2/Makefile index 873e8ced8252..0751e2a0cd82 100644 --- a/drivers/scsi/sym53c8xx_2/Makefile +++ b/drivers/scsi/sym53c8xx_2/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver. sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h index 62d29cfac9e4..11f5dc29aa59 100644 --- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h +++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SYM53C8XX_H diff --git a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h index defccc477d1e..317289ee04a7 100644 --- a/drivers/scsi/sym53c8xx_2/sym_defs.h +++ b/drivers/scsi/sym53c8xx_2/sym_defs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SYM_DEFS_H diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c index 91db17727963..6d7651a7847e 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw.c +++ b/drivers/scsi/sym53c8xx_2/sym_fw.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sym_glue.h" diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.h b/drivers/scsi/sym53c8xx_2/sym_fw.h index ae7e0f9e93fc..bbba011e7612 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SYM_FW_H diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h index 63952ee300b5..d98ec67f0aae 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw1.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h index c87d72443a16..4d1779b2a409 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw2.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 57f6d63e4c40..2ca018ce796f 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -22,20 +23,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/ctype.h> #include <linux/init.h> diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h index e34801ae5d69..7d5c9b988b5b 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.h +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SYM_GLUE_H diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 0a2a54517b15..a428cae4535b 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -22,20 +23,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/slab.h> @@ -3072,6 +3059,7 @@ static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb sym_print_addr(cp->cmd, "%s\n", s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n"); } + /* fall through */ default: /* S_INT, S_INT_COND_MET, S_CONFLICT */ sym_complete_error (np, cp); break; @@ -4632,6 +4620,7 @@ static void sym_int_sir(struct sym_hcb *np) * Negotiation failed. * Target does not want answer message. */ + /* fall through */ case SIR_NEGO_PROTO: sym_nego_default(np, tp, cp); goto out; diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index a141b1758033..9231a2899064 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/gfp.h> diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c index 6f9af0de7ec3..eb5c045c7c59 100644 --- a/drivers/scsi/sym53c8xx_2/sym_malloc.c +++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sym_glue.h" diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h index 96c15145902c..ef419b7ec3e9 100644 --- a/drivers/scsi/sym53c8xx_2/sym_misc.h +++ b/drivers/scsi/sym53c8xx_2/sym_misc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SYM_MISC_H diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c index 5662fbb3ff60..dd3f07b31612 100644 --- a/drivers/scsi/sym53c8xx_2/sym_nvram.c +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sym_glue.h" @@ -708,6 +695,7 @@ static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram) data, len); if (!x) break; + /* fall through */ default: x = sym_read_T93C46_nvram(np, nvram); break; diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h index bdfbbb083b69..d07da39cc240 100644 --- a/drivers/scsi/sym53c8xx_2/sym_nvram.h +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family * of PCI-SCSI IO processors. @@ -21,20 +22,6 @@ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.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 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SYM_NVRAM_H diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 6db37cf306b0..0b845ab7c3bf 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -99,6 +99,7 @@ config SCSI_UFS_DWC_TC_PLATFORM config SCSI_UFS_QCOM tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM + select RESET_CONTROLLER help This selects the QCOM specific additions to UFSHCD platform driver. UFS host on QCOM needs some vendor specific configuration before @@ -108,6 +109,20 @@ config SCSI_UFS_QCOM Select this if you have UFS controller on QCOM chipset. If unsure, say N. +config SCSI_UFS_MEDIATEK + tristate "Mediatek specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK + select PHY_MTK_UFS + help + This selects the Mediatek specific additions to UFSHCD platform driver. + UFS host on Mediatek needs some vendor specific configuration before + accessing the hardware which includes PHY configuration and vendor + specific registers. + + Select this if you have UFS controller on Mediatek chipset. + + If unsure, say N. + config SCSI_UFS_HISI tristate "Hisilicon specific hooks to UFS controller platform driver" depends on (ARCH_HISI || COMPILE_TEST) && SCSI_UFSHCD_PLATFORM diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index a3bd70c3652c..2a9097939bcb 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -10,3 +10,4 @@ ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o +obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index 4a37b4f57164..86dbb723f3ac 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -17,7 +17,8 @@ #include "ufshcd-pltfrm.h" -#define CDNS_UFS_REG_HCLKDIV 0xFC +#define CDNS_UFS_REG_HCLKDIV 0xFC +#define CDNS_UFS_REG_PHY_XCFGD1 0x113C /** * Sets HCLKDIV register value based on the core_clk @@ -77,11 +78,66 @@ static int cdns_ufs_setup_clocks(struct ufs_hba *hba, bool on, return cdns_ufs_set_hclkdiv(hba); } -static struct ufs_hba_variant_ops cdns_pltfm_hba_vops = { +/** + * cdns_ufs_init - performs additional ufs initialization + * @hba: host controller instance + * + * Returns status of initialization + */ +static int cdns_ufs_init(struct ufs_hba *hba) +{ + int status = 0; + + if (hba->vops && hba->vops->phy_initialization) + status = hba->vops->phy_initialization(hba); + + return status; +} + +/** + * cdns_ufs_m31_16nm_phy_initialization - performs m31 phy initialization + * @hba: host controller instance + * + * Always returns 0 + */ +static int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba) +{ + u32 data; + + /* Increase RX_Advanced_Min_ActivateTime_Capability */ + data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1); + data |= BIT(24); + ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1); + + return 0; +} + +static const struct ufs_hba_variant_ops cdns_ufs_pltfm_hba_vops = { + .name = "cdns-ufs-pltfm", + .setup_clocks = cdns_ufs_setup_clocks, +}; + +static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { .name = "cdns-ufs-pltfm", + .init = cdns_ufs_init, .setup_clocks = cdns_ufs_setup_clocks, + .phy_initialization = cdns_ufs_m31_16nm_phy_initialization, +}; + +static const struct of_device_id cdns_ufs_of_match[] = { + { + .compatible = "cdns,ufshc", + .data = &cdns_ufs_pltfm_hba_vops, + }, + { + .compatible = "cdns,ufshc-m31-16nm", + .data = &cdns_ufs_m31_16nm_pltfm_hba_vops, + }, + { }, }; +MODULE_DEVICE_TABLE(of, cdns_ufs_of_match); + /** * cdns_ufs_pltfrm_probe - probe routine of the driver * @pdev: pointer to platform device handle @@ -91,10 +147,15 @@ static struct ufs_hba_variant_ops cdns_pltfm_hba_vops = { static int cdns_ufs_pltfrm_probe(struct platform_device *pdev) { int err; + const struct of_device_id *of_id; + struct ufs_hba_variant_ops *vops; struct device *dev = &pdev->dev; + of_id = of_match_node(cdns_ufs_of_match, dev->of_node); + vops = (struct ufs_hba_variant_ops *)of_id->data; + /* Perform generic probe */ - err = ufshcd_pltfrm_init(pdev, &cdns_pltfm_hba_vops); + err = ufshcd_pltfrm_init(pdev, vops); if (err) dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); @@ -115,13 +176,6 @@ static int cdns_ufs_pltfrm_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id cdns_ufs_of_match[] = { - { .compatible = "cdns,ufshc" }, - {}, -}; - -MODULE_DEVICE_TABLE(of, cdns_ufs_of_match); - static const struct dev_pm_ops cdns_ufs_dev_pm_ops = { .suspend = ufshcd_pltfrm_suspend, .resume = ufshcd_pltfrm_resume, diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c index 2f41722a8c28..67a6a61154b7 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pci.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "ufshcd.h" diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c index 6dfe5a9206e9..a1268e4f44d6 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c index 3a8bc6d9cb5b..f954a68f6b4c 100644 --- a/drivers/scsi/ufs/tc-dwc-g210.c +++ b/drivers/scsi/ufs/tc-dwc-g210.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "ufshcd.h" diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h index fb177db1227d..5a506da03f4a 100644 --- a/drivers/scsi/ufs/tc-dwc-g210.h +++ b/drivers/scsi/ufs/tc-dwc-g210.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Synopsys G210 Test Chip driver * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _TC_DWC_G210_H diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 0e855b5afe82..f4d1dca962c4 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon Hixxxx UFS Driver * * Copyright (c) 2016-2017 Linaro Ltd. * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. - * - * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/time.h> @@ -293,108 +291,7 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba, return err; } -struct ufs_hisi_dev_params { - u32 pwm_rx_gear; /* pwm rx gear to work in */ - u32 pwm_tx_gear; /* pwm tx gear to work in */ - u32 hs_rx_gear; /* hs rx gear to work in */ - u32 hs_tx_gear; /* hs tx gear to work in */ - u32 rx_lanes; /* number of rx lanes */ - u32 tx_lanes; /* number of tx lanes */ - u32 rx_pwr_pwm; /* rx pwm working pwr */ - u32 tx_pwr_pwm; /* tx pwm working pwr */ - u32 rx_pwr_hs; /* rx hs working pwr */ - u32 tx_pwr_hs; /* tx hs working pwr */ - u32 hs_rate; /* rate A/B to work in HS */ - u32 desired_working_mode; -}; - -static int ufs_hisi_get_pwr_dev_param( - struct ufs_hisi_dev_params *hisi_param, - struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) -{ - int min_hisi_gear; - int min_dev_gear; - bool is_dev_sup_hs = false; - bool is_hisi_max_hs = false; - - if (dev_max->pwr_rx == FASTAUTO_MODE || dev_max->pwr_rx == FAST_MODE) - is_dev_sup_hs = true; - - if (hisi_param->desired_working_mode == FAST) { - is_hisi_max_hs = true; - min_hisi_gear = min_t(u32, hisi_param->hs_rx_gear, - hisi_param->hs_tx_gear); - } else { - min_hisi_gear = min_t(u32, hisi_param->pwm_rx_gear, - hisi_param->pwm_tx_gear); - } - - /* - * device doesn't support HS but - * hisi_param->desired_working_mode is HS, - * thus device and hisi_param don't agree - */ - if (!is_dev_sup_hs && is_hisi_max_hs) { - pr_err("%s: device not support HS\n", __func__); - return -ENOTSUPP; - } else if (is_dev_sup_hs && is_hisi_max_hs) { - /* - * since device supports HS, it supports FAST_MODE. - * since hisi_param->desired_working_mode is also HS - * then final decision (FAST/FASTAUTO) is done according - * to hisi_params as it is the restricting factor - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - hisi_param->rx_pwr_hs; - } else { - /* - * here hisi_param->desired_working_mode is PWM. - * it doesn't matter whether device supports HS or PWM, - * in both cases hisi_param->desired_working_mode will - * determine the mode - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - hisi_param->rx_pwr_pwm; - } - - /* - * we would like tx to work in the minimum number of lanes - * between device capability and vendor preferences. - * the same decision will be made for rx - */ - agreed_pwr->lane_tx = - min_t(u32, dev_max->lane_tx, hisi_param->tx_lanes); - agreed_pwr->lane_rx = - min_t(u32, dev_max->lane_rx, hisi_param->rx_lanes); - - /* device maximum gear is the minimum between device rx and tx gears */ - min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); - - /* - * if both device capabilities and vendor pre-defined preferences are - * both HS or both PWM then set the minimum gear to be the chosen - * working gear. - * if one is PWM and one is HS then the one that is PWM get to decide - * what is the gear, as it is the one that also decided previously what - * pwr the device will be configured to. - */ - if ((is_dev_sup_hs && is_hisi_max_hs) || - (!is_dev_sup_hs && !is_hisi_max_hs)) - agreed_pwr->gear_rx = agreed_pwr->gear_tx = - min_t(u32, min_dev_gear, min_hisi_gear); - else - agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_hisi_gear; - - agreed_pwr->hs_rate = hisi_param->hs_rate; - - pr_info("ufs final power mode: gear = %d, lane = %d, pwr = %d, rate = %d\n", - agreed_pwr->gear_rx, agreed_pwr->lane_rx, agreed_pwr->pwr_rx, - agreed_pwr->hs_rate); - return 0; -} - -static void ufs_hisi_set_dev_cap(struct ufs_hisi_dev_params *hisi_param) +static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) { hisi_param->rx_lanes = UFS_HISI_LIMIT_NUM_LANES_RX; hisi_param->tx_lanes = UFS_HISI_LIMIT_NUM_LANES_TX; @@ -477,7 +374,7 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { - struct ufs_hisi_dev_params ufs_hisi_cap; + struct ufs_dev_params ufs_hisi_cap; int ret = 0; if (!dev_req_params) { @@ -490,8 +387,8 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: ufs_hisi_set_dev_cap(&ufs_hisi_cap); - ret = ufs_hisi_get_pwr_dev_param( - &ufs_hisi_cap, dev_max_params, dev_req_params); + ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap, + dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); @@ -587,6 +484,10 @@ static int ufs_hisi_init_common(struct ufs_hba *hba) ufshcd_set_variant(hba, host); host->rst = devm_reset_control_get(dev, "rst"); + if (IS_ERR(host->rst)) { + dev_err(dev, "%s: failed to get reset control\n", __func__); + return PTR_ERR(host->rst); + } ufs_hisi_set_pm_lvl(hba); diff --git a/drivers/scsi/ufs/ufs-hisi.h b/drivers/scsi/ufs/ufs-hisi.h index 667dfe39b57e..3231d3d81c98 100644 --- a/drivers/scsi/ufs/ufs-hisi.h +++ b/drivers/scsi/ufs/ufs-hisi.h @@ -1,8 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017, HiSilicon. All rights reserved. - * - * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #ifndef UFS_HISI_H_ diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c new file mode 100644 index 000000000000..0f6ff33ce52e --- /dev/null +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 MediaTek Inc. + * Authors: + * Stanley Chu <stanley.chu@mediatek.com> + * Peter Wang <peter.wang@mediatek.com> + */ + +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> + +#include "ufshcd.h" +#include "ufshcd-pltfrm.h" +#include "unipro.h" +#include "ufs-mediatek.h" + +static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) +{ + u32 tmp; + + if (enable) { + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + tmp = tmp | + (1 << RX_SYMBOL_CLK_GATE_EN) | + (1 << SYS_CLK_GATE_EN) | + (1 << TX_CLK_GATE_EN); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp); + tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp); + } else { + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) | + (1 << SYS_CLK_GATE_EN) | + (1 << TX_CLK_GATE_EN)); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp); + tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp); + } +} + +static int ufs_mtk_bind_mphy(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + struct device *dev = hba->dev; + struct device_node *np = dev->of_node; + int err = 0; + + host->mphy = devm_of_phy_get_by_index(dev, np, 0); + + if (host->mphy == ERR_PTR(-EPROBE_DEFER)) { + /* + * UFS driver might be probed before the phy driver does. + * In that case we would like to return EPROBE_DEFER code. + */ + err = -EPROBE_DEFER; + dev_info(dev, + "%s: required phy hasn't probed yet. err = %d\n", + __func__, err); + } else if (IS_ERR(host->mphy)) { + err = PTR_ERR(host->mphy); + dev_info(dev, "%s: PHY get failed %d\n", __func__, err); + } + + if (err) + host->mphy = NULL; + + return err; +} + +/** + * ufs_mtk_setup_clocks - enables/disable clocks + * @hba: host controller instance + * @on: If true, enable clocks else disable them. + * @status: PRE_CHANGE or POST_CHANGE notify + * + * Returns 0 on success, non-zero on failure. + */ +static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, + enum ufs_notify_change_status status) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + int ret = -EINVAL; + + /* + * In case ufs_mtk_init() is not yet done, simply ignore. + * This ufs_mtk_setup_clocks() shall be called from + * ufs_mtk_init() after init is done. + */ + if (!host) + return 0; + + switch (status) { + case PRE_CHANGE: + if (!on) + ret = phy_power_off(host->mphy); + break; + case POST_CHANGE: + if (on) + ret = phy_power_on(host->mphy); + break; + } + + return ret; +} + +/** + * ufs_mtk_init - find other essential mmio bases + * @hba: host controller instance + * + * Binds PHY with controller and powers up PHY enabling clocks + * and regulators. + * + * Returns -EPROBE_DEFER if binding fails, returns negative error + * on phy power up failure and returns zero on success. + */ +static int ufs_mtk_init(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host; + struct device *dev = hba->dev; + int err = 0; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + err = -ENOMEM; + dev_info(dev, "%s: no memory for mtk ufs host\n", __func__); + goto out; + } + + host->hba = hba; + ufshcd_set_variant(hba, host); + + err = ufs_mtk_bind_mphy(hba); + if (err) + goto out_variant_clear; + + /* + * ufshcd_vops_init() is invoked after + * ufshcd_setup_clock(true) in ufshcd_hba_init() thus + * phy clock setup is skipped. + * + * Enable phy clocks specifically here. + */ + ufs_mtk_setup_clocks(hba, true, POST_CHANGE); + + goto out; + +out_variant_clear: + ufshcd_set_variant(hba, NULL); +out: + return err; +} + +static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, + struct ufs_pa_layer_attr *dev_max_params, + struct ufs_pa_layer_attr *dev_req_params) +{ + struct ufs_dev_params host_cap; + int ret; + + host_cap.tx_lanes = UFS_MTK_LIMIT_NUM_LANES_TX; + host_cap.rx_lanes = UFS_MTK_LIMIT_NUM_LANES_RX; + host_cap.hs_rx_gear = UFS_MTK_LIMIT_HSGEAR_RX; + host_cap.hs_tx_gear = UFS_MTK_LIMIT_HSGEAR_TX; + host_cap.pwm_rx_gear = UFS_MTK_LIMIT_PWMGEAR_RX; + host_cap.pwm_tx_gear = UFS_MTK_LIMIT_PWMGEAR_TX; + host_cap.rx_pwr_pwm = UFS_MTK_LIMIT_RX_PWR_PWM; + host_cap.tx_pwr_pwm = UFS_MTK_LIMIT_TX_PWR_PWM; + host_cap.rx_pwr_hs = UFS_MTK_LIMIT_RX_PWR_HS; + host_cap.tx_pwr_hs = UFS_MTK_LIMIT_TX_PWR_HS; + host_cap.hs_rate = UFS_MTK_LIMIT_HS_RATE; + host_cap.desired_working_mode = + UFS_MTK_LIMIT_DESIRED_MODE; + + ret = ufshcd_get_pwr_dev_param(&host_cap, + dev_max_params, + dev_req_params); + if (ret) { + pr_info("%s: failed to determine capabilities\n", + __func__); + } + + return ret; +} + +static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, + enum ufs_notify_change_status stage, + struct ufs_pa_layer_attr *dev_max_params, + struct ufs_pa_layer_attr *dev_req_params) +{ + int ret = 0; + + switch (stage) { + case PRE_CHANGE: + ret = ufs_mtk_pre_pwr_change(hba, dev_max_params, + dev_req_params); + break; + case POST_CHANGE: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_mtk_pre_link(struct ufs_hba *hba) +{ + int ret; + u32 tmp; + + /* disable deep stall */ + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + if (ret) + return ret; + + tmp &= ~(1 << 6); + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + return ret; +} + +static int ufs_mtk_post_link(struct ufs_hba *hba) +{ + /* disable device LCC */ + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + + /* enable unipro clock gating feature */ + ufs_mtk_cfg_unipro_cg(hba, true); + + return 0; +} + +static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status stage) +{ + int ret = 0; + + switch (stage) { + case PRE_CHANGE: + ret = ufs_mtk_pre_link(hba); + break; + case POST_CHANGE: + ret = ufs_mtk_post_link(hba); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (ufshcd_is_link_hibern8(hba)) + phy_power_off(host->mphy); + + return 0; +} + +static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (ufshcd_is_link_hibern8(hba)) + phy_power_on(host->mphy); + + return 0; +} + +/** + * struct ufs_hba_mtk_vops - UFS MTK specific variant operations + * + * The variant operations configure the necessary controller and PHY + * handshake during initialization. + */ +static struct ufs_hba_variant_ops ufs_hba_mtk_vops = { + .name = "mediatek.ufshci", + .init = ufs_mtk_init, + .setup_clocks = ufs_mtk_setup_clocks, + .link_startup_notify = ufs_mtk_link_startup_notify, + .pwr_change_notify = ufs_mtk_pwr_change_notify, + .suspend = ufs_mtk_suspend, + .resume = ufs_mtk_resume, +}; + +/** + * ufs_mtk_probe - probe routine of the driver + * @pdev: pointer to Platform device handle + * + * Return zero for success and non-zero for failure + */ +static int ufs_mtk_probe(struct platform_device *pdev) +{ + int err; + struct device *dev = &pdev->dev; + + /* perform generic probe */ + err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops); + if (err) + dev_info(dev, "probe failed %d\n", err); + + return err; +} + +/** + * ufs_mtk_remove - set driver_data of the device to NULL + * @pdev: pointer to platform device handle + * + * Always return 0 + */ +static int ufs_mtk_remove(struct platform_device *pdev) +{ + struct ufs_hba *hba = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&(pdev)->dev); + ufshcd_remove(hba); + return 0; +} + +static const struct of_device_id ufs_mtk_of_match[] = { + { .compatible = "mediatek,mt8183-ufshci"}, + {}, +}; + +static const struct dev_pm_ops ufs_mtk_pm_ops = { + .suspend = ufshcd_pltfrm_suspend, + .resume = ufshcd_pltfrm_resume, + .runtime_suspend = ufshcd_pltfrm_runtime_suspend, + .runtime_resume = ufshcd_pltfrm_runtime_resume, + .runtime_idle = ufshcd_pltfrm_runtime_idle, +}; + +static struct platform_driver ufs_mtk_pltform = { + .probe = ufs_mtk_probe, + .remove = ufs_mtk_remove, + .shutdown = ufshcd_pltfrm_shutdown, + .driver = { + .name = "ufshcd-mtk", + .pm = &ufs_mtk_pm_ops, + .of_match_table = ufs_mtk_of_match, + }, +}; + +MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); +MODULE_AUTHOR("Peter Wang <peter.wang@mediatek.com>"); +MODULE_DESCRIPTION("MediaTek UFS Host Driver"); +MODULE_LICENSE("GPL v2"); + +module_platform_driver(ufs_mtk_pltform); diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h new file mode 100644 index 000000000000..19f8c42fe06f --- /dev/null +++ b/drivers/scsi/ufs/ufs-mediatek.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 MediaTek Inc. + */ + +#ifndef _UFS_MEDIATEK_H +#define _UFS_MEDIATEK_H + +/* + * Vendor specific pre-defined parameters + */ +#define UFS_MTK_LIMIT_NUM_LANES_RX 1 +#define UFS_MTK_LIMIT_NUM_LANES_TX 1 +#define UFS_MTK_LIMIT_HSGEAR_RX UFS_HS_G3 +#define UFS_MTK_LIMIT_HSGEAR_TX UFS_HS_G3 +#define UFS_MTK_LIMIT_PWMGEAR_RX UFS_PWM_G4 +#define UFS_MTK_LIMIT_PWMGEAR_TX UFS_PWM_G4 +#define UFS_MTK_LIMIT_RX_PWR_PWM SLOW_MODE +#define UFS_MTK_LIMIT_TX_PWR_PWM SLOW_MODE +#define UFS_MTK_LIMIT_RX_PWR_HS FAST_MODE +#define UFS_MTK_LIMIT_TX_PWR_HS FAST_MODE +#define UFS_MTK_LIMIT_HS_RATE PA_HS_MODE_B +#define UFS_MTK_LIMIT_DESIRED_MODE UFS_HS_MODE + +/* + * Other attributes + */ +#define VS_DEBUGCLOCKENABLE 0xD0A1 +#define VS_SAVEPOWERCONTROL 0xD0A6 +#define VS_UNIPROPOWERDOWNCONTROL 0xD0A8 + +/* + * VS_DEBUGCLOCKENABLE + */ +enum { + TX_SYMBOL_CLK_REQ_FORCE = 5, +}; + +/* + * VS_SAVEPOWERCONTROL + */ +enum { + RX_SYMBOL_CLK_GATE_EN = 0, + SYS_CLK_GATE_EN = 2, + TX_CLK_GATE_EN = 3, +}; + +struct ufs_mtk_host { + struct ufs_hba *hba; + struct phy *mphy; +}; + +#endif /* !_UFS_MEDIATEK_H */ diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 3aeadb14aae1..ee4b1da1e223 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1,21 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2016, Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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/acpi.h> #include <linux/time.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> +#include <linux/reset-controller.h> #include "ufshcd.h" #include "ufshcd-pltfrm.h" @@ -49,6 +42,11 @@ static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, u32 clk_cycles); +static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd) +{ + return container_of(rcd, struct ufs_qcom_host, rcdev); +} + static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len, const char *prefix, void *priv) { @@ -164,6 +162,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) int err = 0; struct device *dev = host->hba->dev; + if (has_acpi_companion(dev)) + return 0; + err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk", &host->rx_l0_sync_clk, false); if (err) @@ -255,11 +256,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) if (is_rate_B) phy_set_mode(phy, PHY_MODE_UFS_HS_B); - /* Assert PHY reset and apply PHY calibration values */ - ufs_qcom_assert_reset(hba); - /* provide 1ms delay to let the reset pulse propagate */ - usleep_range(1000, 1100); - /* phy initialization - calibrate the phy */ ret = phy_init(phy); if (ret) { @@ -268,15 +264,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) goto out; } - /* De-assert PHY reset and start serdes */ - ufs_qcom_deassert_reset(hba); - - /* - * after reset deassertion, phy will need all ref clocks, - * voltage, current to settle down before starting serdes. - */ - usleep_range(1000, 1100); - /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); if (ret) { @@ -290,7 +277,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return 0; out_disable_phy: - ufs_qcom_assert_reset(hba); phy_exit(phy); out: return ret; @@ -554,21 +540,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufs_qcom_disable_lane_clks(host); phy_power_off(phy); - /* Assert PHY soft reset */ - ufs_qcom_assert_reset(hba); - goto out; - } - - /* - * If UniPro link is not active, PHY ref_clk, main PHY analog power - * rail and low noise analog power rail for PLL can be switched off. - */ - if (!ufs_qcom_is_link_active(hba)) { + } else if (!ufs_qcom_is_link_active(hba)) { ufs_qcom_disable_lane_clks(host); - phy_power_off(phy); } -out: return ret; } @@ -578,118 +553,25 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) struct phy *phy = host->generic_phy; int err; - err = phy_power_on(phy); - if (err) { - dev_err(hba->dev, "%s: failed enabling regs, err = %d\n", - __func__, err); - goto out; - } - - err = ufs_qcom_enable_lane_clks(host); - if (err) - goto out; - - hba->is_sys_suspended = false; - -out: - return err; -} - -struct ufs_qcom_dev_params { - u32 pwm_rx_gear; /* pwm rx gear to work in */ - u32 pwm_tx_gear; /* pwm tx gear to work in */ - u32 hs_rx_gear; /* hs rx gear to work in */ - u32 hs_tx_gear; /* hs tx gear to work in */ - u32 rx_lanes; /* number of rx lanes */ - u32 tx_lanes; /* number of tx lanes */ - u32 rx_pwr_pwm; /* rx pwm working pwr */ - u32 tx_pwr_pwm; /* tx pwm working pwr */ - u32 rx_pwr_hs; /* rx hs working pwr */ - u32 tx_pwr_hs; /* tx hs working pwr */ - u32 hs_rate; /* rate A/B to work in HS */ - u32 desired_working_mode; -}; + if (ufs_qcom_is_link_off(hba)) { + err = phy_power_on(phy); + if (err) { + dev_err(hba->dev, "%s: failed PHY power on: %d\n", + __func__, err); + return err; + } -static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, - struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) -{ - int min_qcom_gear; - int min_dev_gear; - bool is_dev_sup_hs = false; - bool is_qcom_max_hs = false; - - if (dev_max->pwr_rx == FAST_MODE) - is_dev_sup_hs = true; - - if (qcom_param->desired_working_mode == FAST) { - is_qcom_max_hs = true; - min_qcom_gear = min_t(u32, qcom_param->hs_rx_gear, - qcom_param->hs_tx_gear); - } else { - min_qcom_gear = min_t(u32, qcom_param->pwm_rx_gear, - qcom_param->pwm_tx_gear); - } + err = ufs_qcom_enable_lane_clks(host); + if (err) + return err; - /* - * device doesn't support HS but qcom_param->desired_working_mode is - * HS, thus device and qcom_param don't agree - */ - if (!is_dev_sup_hs && is_qcom_max_hs) { - pr_err("%s: failed to agree on power mode (device doesn't support HS but requested power is HS)\n", - __func__); - return -ENOTSUPP; - } else if (is_dev_sup_hs && is_qcom_max_hs) { - /* - * since device supports HS, it supports FAST_MODE. - * since qcom_param->desired_working_mode is also HS - * then final decision (FAST/FASTAUTO) is done according - * to qcom_params as it is the restricting factor - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - qcom_param->rx_pwr_hs; - } else { - /* - * here qcom_param->desired_working_mode is PWM. - * it doesn't matter whether device supports HS or PWM, - * in both cases qcom_param->desired_working_mode will - * determine the mode - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - qcom_param->rx_pwr_pwm; + } else if (!ufs_qcom_is_link_active(hba)) { + err = ufs_qcom_enable_lane_clks(host); + if (err) + return err; } - /* - * we would like tx to work in the minimum number of lanes - * between device capability and vendor preferences. - * the same decision will be made for rx - */ - agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, - qcom_param->tx_lanes); - agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, - qcom_param->rx_lanes); - - /* device maximum gear is the minimum between device rx and tx gears */ - min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); - - /* - * if both device capabilities and vendor pre-defined preferences are - * both HS or both PWM then set the minimum gear to be the chosen - * working gear. - * if one is PWM and one is HS then the one that is PWM get to decide - * what is the gear, as it is the one that also decided previously what - * pwr the device will be configured to. - */ - if ((is_dev_sup_hs && is_qcom_max_hs) || - (!is_dev_sup_hs && !is_qcom_max_hs)) - agreed_pwr->gear_rx = agreed_pwr->gear_tx = - min_t(u32, min_dev_gear, min_qcom_gear); - else if (!is_dev_sup_hs) - agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_dev_gear; - else - agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_qcom_gear; - - agreed_pwr->hs_rate = qcom_param->hs_rate; + hba->is_sys_suspended = false; return 0; } @@ -920,7 +802,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, { u32 val; struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_qcom_dev_params ufs_qcom_cap; + struct ufs_dev_params ufs_qcom_cap; int ret = 0; if (!dev_req_params) { @@ -959,9 +841,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ufs_qcom_cap.hs_rx_gear = UFS_HS_G2; } - ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap, + dev_max_params, + dev_req_params); if (ret) { pr_err("%s: failed to determine capabilities\n", __func__); @@ -1118,8 +1000,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, return 0; if (on && (status == POST_CHANGE)) { - phy_power_on(host->generic_phy); - /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) ufs_qcom_dev_ref_clk_ctrl(host, true); @@ -1131,9 +1011,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, if (!ufs_qcom_is_link_active(hba)) { /* disable device ref_clk */ ufs_qcom_dev_ref_clk_ctrl(host, false); - - /* powering off PHY during aggressive clk gating */ - phy_power_off(host->generic_phy); } vote = host->bus_vote.min_bw_vote; @@ -1147,6 +1024,41 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, return err; } +static int +ufs_qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev); + + /* Currently this code only knows about a single reset. */ + WARN_ON(id); + ufs_qcom_assert_reset(host->hba); + /* provide 1ms delay to let the reset pulse propagate. */ + usleep_range(1000, 1100); + return 0; +} + +static int +ufs_qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev); + + /* Currently this code only knows about a single reset. */ + WARN_ON(id); + ufs_qcom_deassert_reset(host->hba); + + /* + * after reset deassertion, phy will need all ref clocks, + * voltage, current to settle down before starting serdes. + */ + usleep_range(1000, 1100); + return 0; +} + +static const struct reset_control_ops ufs_qcom_reset_ops = { + .assert = ufs_qcom_reset_assert, + .deassert = ufs_qcom_reset_deassert, +}; + #define ANDROID_BOOT_DEV_MAX 30 static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; @@ -1191,6 +1103,17 @@ static int ufs_qcom_init(struct ufs_hba *hba) host->hba = hba; ufshcd_set_variant(hba, host); + /* Fire up the reset controller. Failure here is non-fatal. */ + host->rcdev.of_node = dev->of_node; + host->rcdev.ops = &ufs_qcom_reset_ops; + host->rcdev.owner = dev->driver->owner; + host->rcdev.nr_resets = 1; + err = devm_reset_controller_register(dev, &host->rcdev); + if (err) { + dev_warn(dev, "Failed to register reset controller\n"); + err = 0; + } + /* * voting/devoting device ref_clk source is time consuming hence * skip devoting it during aggressive clock gating. This clock @@ -1208,9 +1131,13 @@ static int ufs_qcom_init(struct ufs_hba *hba) __func__, err); goto out_variant_clear; } else if (IS_ERR(host->generic_phy)) { - err = PTR_ERR(host->generic_phy); - dev_err(dev, "%s: PHY get failed %d\n", __func__, err); - goto out_variant_clear; + if (has_acpi_companion(dev)) { + host->generic_phy = NULL; + } else { + err = PTR_ERR(host->generic_phy); + dev_err(dev, "%s: PHY get failed %d\n", __func__, err); + goto out_variant_clear; + } } err = ufs_qcom_bus_register(host); @@ -1680,6 +1607,14 @@ static const struct of_device_id ufs_qcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, ufs_qcom_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id ufs_qcom_acpi_match[] = { + { "QCOM24A5" }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match); +#endif + static const struct dev_pm_ops ufs_qcom_pm_ops = { .suspend = ufshcd_pltfrm_suspend, .resume = ufshcd_pltfrm_resume, @@ -1696,6 +1631,7 @@ static struct platform_driver ufs_qcom_pltform = { .name = "ufshcd-qcom", .pm = &ufs_qcom_pm_ops, .of_match_table = of_match_ptr(ufs_qcom_of_match), + .acpi_match_table = ACPI_PTR(ufs_qcom_acpi_match), }, }; module_platform_driver(ufs_qcom_pltform); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index c114826316eb..001915d1e0e4 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -1,19 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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 UFS_QCOM_H_ #define UFS_QCOM_H_ +#include <linux/reset-controller.h> + #define MAX_UFS_QCOM_HOSTS 1 #define MAX_U32 (~(u32)0) #define MPHY_TX_FSM_STATE 0x41 @@ -237,6 +230,8 @@ struct ufs_qcom_host { /* Bitmask for enabling debug prints */ u32 dbg_print_en; struct ufs_qcom_testbus testbus; + + struct reset_controller_dev rcdev; }; static inline u32 diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index 8d9332bb7d0c..f478685122ff 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -122,7 +122,7 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) { unsigned long flags; - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + if (!ufshcd_is_auto_hibern8_supported(hba)) return; spin_lock_irqsave(hba->host->host_lock, flags); @@ -164,7 +164,7 @@ static ssize_t auto_hibern8_show(struct device *dev, { struct ufs_hba *hba = dev_get_drvdata(dev); - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + if (!ufshcd_is_auto_hibern8_supported(hba)) return -EOPNOTSUPP; return snprintf(buf, PAGE_SIZE, "%d\n", ufshcd_ahit_to_us(hba->ahit)); @@ -177,7 +177,7 @@ static ssize_t auto_hibern8_store(struct device *dev, struct ufs_hba *hba = dev_get_drvdata(dev); unsigned int timer; - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + if (!ufshcd_is_auto_hibern8_supported(hba)) return -EOPNOTSUPP; if (kstrtouint(buf, 0, &timer)) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 21e4ccb5ba6e..99a9c4d16f6b 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -516,7 +516,6 @@ struct ufs_vreg { bool enabled; int min_uV; int max_uV; - int min_uA; int max_uA; }; diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index 869e71f861d6..a9344eb4e047 100644 --- a/drivers/scsi/ufs/ufs_bsg.c +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -122,7 +122,7 @@ static int ufs_bsg_request(struct bsg_job *job) memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE); ret = ufshcd_send_uic_cmd(hba, &uc); if (ret) - dev_dbg(hba->dev, + dev_err(hba->dev, "send uic cmd: error code %d\n", ret); memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE); @@ -149,7 +149,9 @@ static int ufs_bsg_request(struct bsg_job *job) out: bsg_reply->result = ret; job->reply_len = sizeof(struct ufs_bsg_reply); - bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); + /* complete the job here only if no error */ + if (ret == 0) + bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); return ret; } diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index a9bbd34d6b16..fe6cad9b2a0d 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -1,15 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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 _UFS_QUIRKS_H_ diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c index 977b21871a5d..fb9e2ff4f8d2 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.c +++ b/drivers/scsi/ufs/ufshcd-dwc.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * UFS Host driver for Synopsys Designware Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include "ufshcd.h" diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h index c8be295e0ebe..4268ca2eb64c 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.h +++ b/drivers/scsi/ufs/ufshcd-dwc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * UFS Host driver for Synopsys Designware Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _UFSHCD_DWC_H diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index ffe6f82182ba..3b19de3ae9a3 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -200,6 +200,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = { static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, { } /* terminate list */ }; diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 27213676329c..d7d521b394c3 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -39,6 +39,7 @@ #include "ufshcd.h" #include "ufshcd-pltfrm.h" +#include "unipro.h" #define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2 @@ -151,20 +152,12 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name, vreg->name = kstrdup(name, GFP_KERNEL); - /* if fixed regulator no need further initialization */ - snprintf(prop_name, MAX_PROP_SIZE, "%s-fixed-regulator", name); - if (of_property_read_bool(np, prop_name)) - goto out; - snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name); - ret = of_property_read_u32(np, prop_name, &vreg->max_uA); - if (ret) { - dev_err(dev, "%s: unable to find %s err %d\n", - __func__, prop_name, ret); - goto out; + if (of_property_read_u32(np, prop_name, &vreg->max_uA)) { + dev_info(dev, "%s: unable to find %s\n", __func__, prop_name); + vreg->max_uA = 0; } - vreg->min_uA = 0; if (!strcmp(name, "vcc")) { if (of_property_read_bool(np, "vcc-supply-1p8")) { vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV; @@ -290,6 +283,103 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba) } /** + * ufshcd_get_pwr_dev_param - get finally agreed attributes for + * power mode change + * @pltfrm_param: pointer to platform parameters + * @dev_max: pointer to device attributes + * @agreed_pwr: returned agreed attributes + * + * Returns 0 on success, non-zero value on failure + */ +int ufshcd_get_pwr_dev_param(struct ufs_dev_params *pltfrm_param, + struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) +{ + int min_pltfrm_gear; + int min_dev_gear; + bool is_dev_sup_hs = false; + bool is_pltfrm_max_hs = false; + + if (dev_max->pwr_rx == FAST_MODE) + is_dev_sup_hs = true; + + if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { + is_pltfrm_max_hs = true; + min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, + pltfrm_param->hs_tx_gear); + } else { + min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, + pltfrm_param->pwm_tx_gear); + } + + /* + * device doesn't support HS but + * pltfrm_param->desired_working_mode is HS, + * thus device and pltfrm_param don't agree + */ + if (!is_dev_sup_hs && is_pltfrm_max_hs) { + pr_info("%s: device doesn't support HS\n", + __func__); + return -ENOTSUPP; + } else if (is_dev_sup_hs && is_pltfrm_max_hs) { + /* + * since device supports HS, it supports FAST_MODE. + * since pltfrm_param->desired_working_mode is also HS + * then final decision (FAST/FASTAUTO) is done according + * to pltfrm_params as it is the restricting factor + */ + agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; + agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; + } else { + /* + * here pltfrm_param->desired_working_mode is PWM. + * it doesn't matter whether device supports HS or PWM, + * in both cases pltfrm_param->desired_working_mode will + * determine the mode + */ + agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; + agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; + } + + /* + * we would like tx to work in the minimum number of lanes + * between device capability and vendor preferences. + * the same decision will be made for rx + */ + agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, + pltfrm_param->tx_lanes); + agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, + pltfrm_param->rx_lanes); + + /* device maximum gear is the minimum between device rx and tx gears */ + min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); + + /* + * if both device capabilities and vendor pre-defined preferences are + * both HS or both PWM then set the minimum gear to be the chosen + * working gear. + * if one is PWM and one is HS then the one that is PWM get to decide + * what is the gear, as it is the one that also decided previously what + * pwr the device will be configured to. + */ + if ((is_dev_sup_hs && is_pltfrm_max_hs) || + (!is_dev_sup_hs && !is_pltfrm_max_hs)) { + agreed_pwr->gear_rx = + min_t(u32, min_dev_gear, min_pltfrm_gear); + } else if (!is_dev_sup_hs) { + agreed_pwr->gear_rx = min_dev_gear; + } else { + agreed_pwr->gear_rx = min_pltfrm_gear; + } + agreed_pwr->gear_tx = agreed_pwr->gear_rx; + + agreed_pwr->hs_rate = pltfrm_param->hs_rate; + + return 0; +} +EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); + +/** * ufshcd_pltfrm_init - probe routine of the driver * @pdev: pointer to Platform device handle * @vops: pointer to variant ops @@ -340,24 +430,21 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, goto dealloc_host; } - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - ufshcd_init_lanes_per_dir(hba); err = ufshcd_init(hba, mmio_base, irq); if (err) { dev_err(dev, "Initialization failed\n"); - goto out_disable_rpm; + goto dealloc_host; } platform_set_drvdata(pdev, hba); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0; -out_disable_rpm: - pm_runtime_disable(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); dealloc_host: ufshcd_dealloc_host(hba); out: diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h index 1f29e1fd6d52..b79cdf9129a0 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.h +++ b/drivers/scsi/ufs/ufshcd-pltfrm.h @@ -1,14 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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 UFSHCD_PLTFRM_H_ @@ -16,6 +7,27 @@ #include "ufshcd.h" +#define UFS_PWM_MODE 1 +#define UFS_HS_MODE 2 + +struct ufs_dev_params { + u32 pwm_rx_gear; /* pwm rx gear to work in */ + u32 pwm_tx_gear; /* pwm tx gear to work in */ + u32 hs_rx_gear; /* hs rx gear to work in */ + u32 hs_tx_gear; /* hs tx gear to work in */ + u32 rx_lanes; /* number of rx lanes */ + u32 tx_lanes; /* number of tx lanes */ + u32 rx_pwr_pwm; /* rx pwm working pwr */ + u32 tx_pwr_pwm; /* tx pwm working pwr */ + u32 rx_pwr_hs; /* rx hs working pwr */ + u32 tx_pwr_hs; /* tx hs working pwr */ + u32 hs_rate; /* rate A/B to work in HS */ + u32 desired_working_mode; +}; + +int ufshcd_get_pwr_dev_param(struct ufs_dev_params *dev_param, + struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); void ufshcd_pltfrm_shutdown(struct platform_device *pdev); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e040f9dd9ff3..04d3686511c8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1917,7 +1917,8 @@ int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE); /* Get the descriptor */ - if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { + if (hba->dev_cmd.query.descriptor && + lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + GENERAL_UPIU_REQUEST_SIZE; u16 resp_len; @@ -3907,7 +3908,7 @@ static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) { unsigned long flags; - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit) + if (!ufshcd_is_auto_hibern8_supported(hba) || !hba->ahit) return; spin_lock_irqsave(hba->host->host_lock, flags); @@ -4704,10 +4705,10 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) "Reject UPIU not fully implemented\n"); break; default: - result = DID_ERROR << 16; dev_err(hba->dev, "Unexpected request response code = %x\n", result); + result = DID_ERROR << 16; break; } break; @@ -5254,6 +5255,7 @@ static void ufshcd_err_handler(struct work_struct *work) goto skip_err_handling; } if ((hba->saved_err & INT_FATAL_ERRORS) || + (hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) || ((hba->saved_err & UIC_ERROR) && (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR | UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | @@ -5413,6 +5415,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) __func__, hba->uic_error); } +static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, + u32 intr_mask) +{ + if (!ufshcd_is_auto_hibern8_supported(hba)) + return false; + + if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK)) + return false; + + if (hba->active_uic_cmd && + (hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_ENTER || + hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_EXIT)) + return false; + + return true; +} + /** * ufshcd_check_errors - Check for errors that need s/w attention * @hba: per-adapter instance @@ -5431,6 +5450,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba) queue_eh_work = true; } + if (hba->errors & UFSHCD_UIC_HIBERN8_MASK) { + dev_err(hba->dev, + "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n", + __func__, (hba->errors & UIC_HIBERNATE_ENTER) ? + "Enter" : "Exit", + hba->errors, ufshcd_get_upmcrs(hba)); + queue_eh_work = true; + } + if (queue_eh_work) { /* * update the transfer error masks to sticky bits, let's do this @@ -5493,6 +5521,10 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba) static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) { hba->errors = UFSHCD_ERROR_MASK & intr_status; + + if (ufshcd_is_auto_hibern8_error(hba, intr_status)) + hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); + if (hba->errors) ufshcd_check_errors(hba); @@ -6294,19 +6326,19 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, goto out; } - if (hba->vreg_info.vcc) + if (hba->vreg_info.vcc && hba->vreg_info.vcc->max_uA) icc_level = ufshcd_get_max_icc_level( hba->vreg_info.vcc->max_uA, POWER_DESC_MAX_ACTV_ICC_LVLS - 1, &desc_buf[PWR_DESC_ACTIVE_LVLS_VCC_0]); - if (hba->vreg_info.vccq) + if (hba->vreg_info.vccq && hba->vreg_info.vccq->max_uA) icc_level = ufshcd_get_max_icc_level( hba->vreg_info.vccq->max_uA, icc_level, &desc_buf[PWR_DESC_ACTIVE_LVLS_VCCQ_0]); - if (hba->vreg_info.vccq2) + if (hba->vreg_info.vccq2 && hba->vreg_info.vccq2->max_uA) icc_level = ufshcd_get_max_icc_level( hba->vreg_info.vccq2->max_uA, icc_level, @@ -7004,6 +7036,15 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, if (!vreg) return 0; + /* + * "set_load" operation shall be required on those regulators + * which specifically configured current limitation. Otherwise + * zero max_uA may cause unexpected behavior when regulator is + * enabled or set as high power mode. + */ + if (!vreg->max_uA) + return 0; + ret = regulator_set_load(vreg->reg, ua); if (ret < 0) { dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n", @@ -7039,12 +7080,15 @@ static int ufshcd_config_vreg(struct device *dev, name = vreg->name; if (regulator_count_voltages(reg) > 0) { - min_uV = on ? vreg->min_uV : 0; - ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); - if (ret) { - dev_err(dev, "%s: %s set voltage failed, err=%d\n", + if (vreg->min_uV && vreg->max_uV) { + min_uV = on ? vreg->min_uV : 0; + ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); + if (ret) { + dev_err(dev, + "%s: %s set voltage failed, err=%d\n", __func__, name, ret); - goto out; + goto out; + } } uA_load = on ? vreg->max_uA : 0; @@ -7103,9 +7147,6 @@ static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on) struct device *dev = hba->dev; struct ufs_vreg_info *info = &hba->vreg_info; - if (!info) - goto out; - ret = ufshcd_toggle_vreg(dev, info->vcc, on); if (ret) goto out; @@ -7131,10 +7172,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on) { struct ufs_vreg_info *info = &hba->vreg_info; - if (info) - return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on); - - return 0; + return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on); } static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg) @@ -7160,9 +7198,6 @@ static int ufshcd_init_vreg(struct ufs_hba *hba) struct device *dev = hba->dev; struct ufs_vreg_info *info = &hba->vreg_info; - if (!info) - goto out; - ret = ufshcd_get_vreg(dev, info->vcc); if (ret) goto out; @@ -8309,7 +8344,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) UIC_LINK_HIBERN8_STATE); /* Set the default auto-hiberate idle timer value to 150 ms */ - if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) { + if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) { hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) | FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3); } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index ecfa898b9ccc..994d73d03207 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -740,6 +740,11 @@ return true; #endif } +static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba) +{ + return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT); +} + #define ufshcd_writel(hba, val, reg) \ writel((val), (hba)->mmio_base + (reg)) #define ufshcd_readl(hba, reg) \ diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h index ca341fece310..6c290e272106 100644 --- a/drivers/scsi/ufs/ufshci-dwc.h +++ b/drivers/scsi/ufs/ufshci-dwc.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * UFS Host driver for Synopsys Designware Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto <jpinto@synopsys.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _UFSHCI_DWC_H diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 6fa889de5ee5..dbb75cd28dc8 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -144,8 +144,10 @@ enum { #define CONTROLLER_FATAL_ERROR 0x10000 #define SYSTEM_BUS_FATAL_ERROR 0x20000 -#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\ - UIC_HIBERNATE_EXIT |\ +#define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\ + UIC_HIBERNATE_EXIT) + +#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\ UIC_POWER_MODE) #define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK) diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h index 23129d7b2678..f539f873f94d 100644 --- a/drivers/scsi/ufs/unipro.h +++ b/drivers/scsi/ufs/unipro.h @@ -1,12 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * drivers/scsi/ufs/unipro.h * * Copyright (C) 2013 Samsung Electronics Co., Ltd. - * - * 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. */ #ifndef _UNIPRO_H_ @@ -52,7 +48,7 @@ #define RX_HS_UNTERMINATED_ENABLE 0x00A6 #define RX_ENTER_HIBERN8 0x00A7 #define RX_BYPASS_8B10B_ENABLE 0x00A8 -#define RX_TERMINATION_FORCE_ENABLE 0x0089 +#define RX_TERMINATION_FORCE_ENABLE 0x00A9 #define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F #define RX_HIBERN8TIME_CAPABILITY 0x0092 #define RX_REFCLKFREQ 0x00EB diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index f8cb7c23305b..1705398b026a 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Virtio SCSI HBA driver * @@ -7,10 +8,6 @@ * Authors: * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> * Paolo Bonzini <pbonzini@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -77,9 +74,6 @@ struct virtio_scsi { u32 num_queues; - /* If the affinity hint is set for virtqueues */ - bool affinity_hint_set; - struct hlist_node node; /* Protected by event_vq lock */ @@ -659,7 +653,7 @@ static int virtscsi_abort(struct scsi_cmnd *sc) static int virtscsi_map_queues(struct Scsi_Host *shost) { struct virtio_scsi *vscsi = shost_priv(shost); - struct blk_mq_queue_map *qmap = &shost->tag_set.map[0]; + struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; return blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2); } diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index ecee4b3ff073..70008816c91f 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -335,7 +335,7 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx, BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); sge = &ctx->sgl->sge[0]; - for (i = 0; i < count; i++, sg++) { + for (i = 0; i < count; i++, sg = sg_next(sg)) { sge[i].addr = sg_dma_address(sg); sge[i].length = sg_dma_len(sg); sge[i].flags = 0; @@ -763,6 +763,7 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd struct pvscsi_adapter *adapter = shost_priv(host); struct pvscsi_ctx *ctx; unsigned long flags; + unsigned char op; spin_lock_irqsave(&adapter->hw_lock, flags); @@ -775,13 +776,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd } cmd->scsi_done = done; + op = cmd->cmnd[0]; dev_dbg(&cmd->device->sdev_gendev, - "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]); + "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op); spin_unlock_irqrestore(&adapter->hw_lock, flags); - pvscsi_kick_io(adapter, cmd->cmnd[0]); + pvscsi_kick_io(adapter, op); return 0; } diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 74be04f2357c..fb7b289fa09f 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 1996 John Shifflett, GeoLog Consulting * john@geolog.com * jshiffle@netcom.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. */ /* @@ -744,7 +735,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, * source or destination for THIS transfer. */ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; + cmd->SCp.buffer = sg_next(cmd->SCp.buffer); --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index 08abe508e9ad..2edec34c5a42 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * wd33c93.h - Linux device driver definitions for the * Commodore Amiga A2091/590 SCSI controller card @@ -7,17 +8,6 @@ * Copyright (c) 1996 John Shifflett, GeoLog Consulting * john@geolog.com * jshiffle@netcom.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 WD33C93_H #define WD33C93_H diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index e3310e9488d2..edc8a139a60d 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards * Copyright 2013 Ondrej Zary @@ -107,8 +108,15 @@ static inline int wd719x_wait_done(struct wd719x *wd, int timeout) } if (status != WD719X_INT_NOERRORS) { + u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR); + /* we get this after wd719x_dev_reset, it's not an error */ + if (sue == WD719X_SUE_TERM) + return 0; + /* we get this after wd719x_bus_reset, it's not an error */ + if (sue == WD719X_SUE_RESET) + return 0; dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n", - status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR)); + status, sue); return -EIO; } @@ -127,8 +135,10 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun, if (wd719x_wait_ready(wd)) return -ETIMEDOUT; - /* make sure we get NO interrupts */ - dev |= WD719X_DISABLE_INT; + /* disable interrupts except for RESET/ABORT (it breaks them) */ + if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT && + opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET) + dev |= WD719X_DISABLE_INT; wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev); wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun); wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag); @@ -464,6 +474,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd) spin_lock_irqsave(wd->sh->host_lock, flags); result = wd719x_direct_cmd(wd, action, cmd->device->id, cmd->device->lun, cmd->tag, scb->phys, 0); + wd719x_finish_cmd(scb, DID_ABORT); spin_unlock_irqrestore(wd->sh->host_lock, flags); if (result) return FAILED; @@ -476,6 +487,7 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device) int result; unsigned long flags; struct wd719x *wd = shost_priv(cmd->device->host); + struct wd719x_scb *scb, *tmp; dev_info(&wd->pdev->dev, "%s reset requested\n", (opcode == WD719X_CMD_BUSRESET) ? "bus" : "device"); @@ -483,6 +495,12 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device) spin_lock_irqsave(wd->sh->host_lock, flags); result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0, WD719X_WAIT_FOR_SCSI_RESET); + /* flush all SCBs (or all for a device if dev_reset) */ + list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) { + if (opcode == WD719X_CMD_BUSRESET || + scb->cmd->device->id == device) + wd719x_finish_cmd(scb, DID_RESET); + } spin_unlock_irqrestore(wd->sh->host_lock, flags); if (result) return FAILED; @@ -505,22 +523,23 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) struct wd719x *wd = shost_priv(cmd->device->host); struct wd719x_scb *scb, *tmp; unsigned long flags; - int result; dev_info(&wd->pdev->dev, "host reset requested\n"); spin_lock_irqsave(wd->sh->host_lock, flags); - /* Try to reinit the RISC */ - if (wd719x_chip_init(wd) == 0) - result = SUCCESS; - else - result = FAILED; + /* stop the RISC */ + if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0, + WD719X_WAIT_FOR_RISC)) + dev_warn(&wd->pdev->dev, "RISC sleep command failed\n"); + /* disable RISC */ + wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0); /* flush all SCBs */ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) - wd719x_finish_cmd(scb, result); + wd719x_finish_cmd(scb, DID_RESET); spin_unlock_irqrestore(wd->sh->host_lock, flags); - return result; + /* Try to reinit the RISC */ + return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED; } static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev, @@ -672,7 +691,7 @@ static irqreturn_t wd719x_interrupt(int irq, void *dev_id) else dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n"); } else - dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n", + dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n", regs.bytes.OPC); break; case WD719X_INT_PIOREADY: diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 4722660958f8..77bce208210e 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Zalon 53c7xx device driver. * By Richard Hirst (rhirst@linuxcare.com) diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c index aff31991aea9..27b9e2baab1a 100644 --- a/drivers/scsi/zorro7xx.c +++ b/drivers/scsi/zorro7xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux. * Amiga MacroSystemUS WarpEngine SCSI controller. |