From 026104bfa591709689e12434c1bb3b485bf5bfa0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:13:54 -0400 Subject: [PATCH 001/185] scsi: core: add SPDX tags to scsi midlayer files missing licensing information Add the default kernel GPLv2 annotation to SCSI midlayer files missing any licensing information. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 1 + drivers/scsi/scsi.c | 1 + drivers/scsi/scsi_debugfs.h | 1 + drivers/scsi/scsi_error.c | 1 + drivers/scsi/scsi_ioctl.c | 1 + drivers/scsi/scsi_lib.c | 1 + drivers/scsi/scsi_pm.c | 1 + drivers/scsi/scsi_sysfs.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index eaf329db3973..96ed24841c33 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * hosts.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995 Eric Youngdale diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 99a7b9f520ae..49821f138ae0 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * scsi.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale 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_error.c b/drivers/scsi/scsi_error.c index 8e9680572b9f..f490994374f6 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * scsi_error.c Copyright (C) 1997 Eric Youngdale * diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 840d96fe81bc..00397205466b 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Changes: * Arnaldo Carvalho de Melo 08/23/2000 diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0916bd6d22b0..b1b1a1aaa353 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1999 Eric Youngdale * Copyright (C) 2014 Christoph Hellwig diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 7639df91b110..3a5dfbb81622 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * scsi_pm.c Copyright (C) 2010 Alan Stern * diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 3b119ca0cc0c..ff0aea7ac87f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * scsi_sysfs.c * From 22104afd732962ab673f5096ba5565667ea4f2b2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:13:55 -0400 Subject: [PATCH 002/185] scsi: core: switch the remaining scsi midlayer files to use SPDX tags Use the GPLv2 SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_logging.c | 3 +-- drivers/scsi/scsi_sysctl.c | 2 +- drivers/scsi/scsi_trace.c | 14 +------------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index bd70339c1242..ca582218d72d 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * scsi_logging.c * * Copyright (C) 2014 SUSE Linux Products GmbH * Copyright (C) 2014 Hannes Reinecke - * - * This file is released under the GPLv2 */ #include diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c index 546f16299ef9..c74a965a51a7 100644 --- a/drivers/scsi/scsi_sysctl.c +++ b/drivers/scsi/scsi_sysctl.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2003 Christoph Hellwig. - * Released under GPL v2. */ #include diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 0ff083bbf5b1..6ae168fcc119 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2010 FUJITSU LIMITED * Copyright (C) 2010 Tomohiro Kusumi - * - * 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 #include From 17bd0fb319a77d951aa989794898bc2d1caa05a8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:13:56 -0400 Subject: [PATCH 003/185] scsi: scsi_netlink: remove duplicate GPL boilerplate text The SCSI netlink uapi header already has a proper SPDX tag, remove the duplicate boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_netlink.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/uapi/scsi/scsi_netlink.h b/include/uapi/scsi/scsi_netlink.h index 5ccc2333acab..5dd382054e45 100644 --- a/include/uapi/scsi/scsi_netlink.h +++ b/include/uapi/scsi/scsi_netlink.h @@ -4,21 +4,6 @@ * Used for the posting of outbound SCSI transport events * * 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 - * */ #ifndef SCSI_NETLINK_H #define SCSI_NETLINK_H From 2711770056aa5af970cf10e363ec496e79fb9735 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:13:57 -0400 Subject: [PATCH 004/185] scsi: scsi_transport.h: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- include/scsi/scsi_transport.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h index a3dcb1bfb362..a0643b9f6f13 100644 --- a/include/scsi/scsi_transport.h +++ b/include/scsi/scsi_transport.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Transport specific attributes. * * 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 */ #ifndef SCSI_TRANSPORT_H #define SCSI_TRANSPORT_H From b01211b9c3b2f4a09874bb454c12eeaf65363e32 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:13:58 -0400 Subject: [PATCH 005/185] scsi: scsi_transport_fc: remove duplicate GPL boilerplate text The FC transport class uapi headers already have proper SPDX tags, remove the duplicate boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_fc.h | 15 --------------- include/uapi/scsi/scsi_netlink_fc.h | 15 --------------- 2 files changed, 30 deletions(-) diff --git a/include/uapi/scsi/scsi_bsg_fc.h b/include/uapi/scsi/scsi_bsg_fc.h index 62597d86beed..52f32a60d056 100644 --- a/include/uapi/scsi/scsi_bsg_fc.h +++ b/include/uapi/scsi/scsi_bsg_fc.h @@ -3,21 +3,6 @@ * FC Transport BSG Interface * * Copyright (C) 2008 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 - * */ #ifndef SCSI_BSG_FC_H diff --git a/include/uapi/scsi/scsi_netlink_fc.h b/include/uapi/scsi/scsi_netlink_fc.h index 060f563c38a2..a39023579051 100644 --- a/include/uapi/scsi/scsi_netlink_fc.h +++ b/include/uapi/scsi/scsi_netlink_fc.h @@ -3,21 +3,6 @@ * FC 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 - * */ #ifndef SCSI_NETLINK_FC_H #define SCSI_NETLINK_FC_H From 518397c216aab84a65f7f3a96ff0582233c5e0ff Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:13:59 -0400 Subject: [PATCH 006/185] scsi: scsi_transport_fc: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_fc.c | 18 +----------------- include/scsi/scsi_transport_fc.h | 18 +----------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index d9e3cf3721f6..8be503da7edb 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1,24 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * 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... diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index b375c3303fe2..b990091d5c20 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -1,24 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * 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... From 7d38479a74bcb6f37d10ec94b7260332395b0bc2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:00 -0400 Subject: [PATCH 007/185] scsi: scsi_transport_iscsi: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 15 +-------------- include/scsi/scsi_transport_iscsi.h | 15 +-------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 0a82e93566dc..828b242e28b0 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+ /* * 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 #include diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b266d2a3bcb1..98149e82926b 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * iSCSI transport class definitions * @@ -5,20 +6,6 @@ * Copyright (C) Mike Christie, 2004 - 2006 * 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. */ #ifndef SCSI_TRANSPORT_ISCSI_H #define SCSI_TRANSPORT_ISCSI_H From 390363c1dd69189f2ab82a6ae992ab64cb5b6c96 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:01 -0400 Subject: [PATCH 008/185] scsi: scsi_transport_sas: switch to SPDX tags Use the the GPLv2 SPDX tag instead of a free form blurb. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 60f1a81d2034..fbfe01b06eb3 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 /* * Copyright (C) 2005-2006 Dell Inc. - * Released under GPL v2. * * Serial Attached SCSI (SAS) transport class. * From 838b709053864779e9aa4be5f7b4d5ac69af5715 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:02 -0400 Subject: [PATCH 009/185] scsi: scsi_transport_spi: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_spi.c | 15 +-------------- include/scsi/scsi_transport_spi.h | 15 +-------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 40b85b752b79..474d2ffad9d8 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+ /* * Parallel SCSI (SPI) transport specific attributes exported to sysfs. * * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. * Copyright (c) 2004, 2005 James Bottomley - * - * 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 #include diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h index a4fa52b4d5c5..12516d16933d 100644 --- a/include/scsi/scsi_transport_spi.h +++ b/include/scsi/scsi_transport_spi.h @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Parallel SCSI (SPI) 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 */ #ifndef SCSI_TRANSPORT_SPI_H #define SCSI_TRANSPORT_SPI_H From 1d3439fa8792aa9568f9852cd126fa59f5899655 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:03 -0400 Subject: [PATCH 010/185] scsi: scsi_transport_srp: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Acked-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_srp.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 4e46fdb2d7c9..280d9029759a 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 /* * SCSI RDMA (SRP) transport class * * Copyright (C) 2007 FUJITA Tomonori - * - * 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 #include From 402b0e32609e72baed4ae6504a37c98bb1507822 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:04 -0400 Subject: [PATCH 011/185] scsi: libfc: remove duplicate GPL boilerplate text The libfc uapi headers already have proper SPDX tags, remove the duplicate boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- include/uapi/scsi/fc/fc_els.h | 13 ------------- include/uapi/scsi/fc/fc_fs.h | 13 ------------- include/uapi/scsi/fc/fc_gs.h | 13 ------------- include/uapi/scsi/fc/fc_ns.h | 13 ------------- 4 files changed, 52 deletions(-) diff --git a/include/uapi/scsi/fc/fc_els.h b/include/uapi/scsi/fc/fc_els.h index a81c53508cc6..76f627f0d13b 100644 --- a/include/uapi/scsi/fc/fc_els.h +++ b/include/uapi/scsi/fc/fc_els.h @@ -2,19 +2,6 @@ /* * 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/include/uapi/scsi/fc/fc_fs.h b/include/uapi/scsi/fc/fc_fs.h index 8c0a292a61ed..0dab49dbb2f7 100644 --- a/include/uapi/scsi/fc/fc_fs.h +++ b/include/uapi/scsi/fc/fc_fs.h @@ -2,19 +2,6 @@ /* * 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/include/uapi/scsi/fc/fc_gs.h b/include/uapi/scsi/fc/fc_gs.h index 2153f3524555..effb4c662fe5 100644 --- a/include/uapi/scsi/fc/fc_gs.h +++ b/include/uapi/scsi/fc/fc_gs.h @@ -2,19 +2,6 @@ /* * 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/include/uapi/scsi/fc/fc_ns.h b/include/uapi/scsi/fc/fc_ns.h index 015e5e1ce8f1..4cf0a40a099a 100644 --- a/include/uapi/scsi/fc/fc_ns.h +++ b/include/uapi/scsi/fc/fc_ns.h @@ -2,19 +2,6 @@ /* * 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 */ From d4fd6347552791c2b79ceacaa6e87c16fcac6db1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:05 -0400 Subject: [PATCH 012/185] scsi: libfc: switch to SPDX tags Use the the GPLv2 SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libfc/fc_disc.c | 14 +------------- drivers/scsi/libfc/fc_elsct.c | 14 +------------- drivers/scsi/libfc/fc_exch.c | 14 +------------- drivers/scsi/libfc/fc_fcp.c | 14 +------------- drivers/scsi/libfc/fc_frame.c | 14 +------------- drivers/scsi/libfc/fc_libfc.c | 14 +------------- drivers/scsi/libfc/fc_libfc.h | 14 +------------- drivers/scsi/libfc/fc_lport.c | 14 +------------- drivers/scsi/libfc/fc_npiv.c | 14 +------------- drivers/scsi/libfc/fc_rport.c | 14 +------------- include/scsi/fc/fc_encaps.h | 14 +------------- include/scsi/fc/fc_fc2.h | 14 +------------- include/scsi/fc/fc_fcoe.h | 14 +------------- include/scsi/fc/fc_fcp.h | 14 +------------- include/scsi/fc/fc_fip.h | 14 +------------- include/scsi/fc/fc_ms.h | 17 +++-------------- include/scsi/libfc.h | 14 +------------- 17 files changed, 19 insertions(+), 222 deletions(-) diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index f969a71348ef..4b00477e51e7 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 /* * 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..8e033facded7 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 /* * 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..025cd2ff9f65 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 /* * 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..0e619e7481db 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 /* * 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..56c390a365b7 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 /* * 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..9a6927d17941 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 /* * 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..01269b66e625 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 */ /* * 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..1db7ef904ab7 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 /* * 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..fa1d585b9041 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 /* * 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..0da34c7a6866 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 /* * 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/include/scsi/fc/fc_encaps.h b/include/scsi/fc/fc_encaps.h index f180c3e16220..a7bded5e1fe5 100644 --- a/include/scsi/fc/fc_encaps.h +++ b/include/scsi/fc/fc_encaps.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * 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 */ #ifndef _FC_ENCAPS_H_ diff --git a/include/scsi/fc/fc_fc2.h b/include/scsi/fc/fc_fc2.h index 0b2671431305..fa95de50f7dc 100644 --- a/include/scsi/fc/fc_fc2.h +++ b/include/scsi/fc/fc_fc2.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * 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/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h index d5dcd6062815..e6c086c06777 100644 --- a/include/scsi/fc/fc_fcoe.h +++ b/include/scsi/fc/fc_fcoe.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * 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/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 9c8702942b61..35b07e83b9bd 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * 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/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h index 9710254fd98c..e0a3423ba09e 100644 --- a/include/scsi/fc/fc_fip.h +++ b/include/scsi/fc/fc_fip.h @@ -1,18 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _FC_FIP_H_ #define _FC_FIP_H_ diff --git a/include/scsi/fc/fc_ms.h b/include/scsi/fc/fc_ms.h index f52b921b5c70..78c82e437bb2 100644 --- a/include/scsi/fc/fc_ms.h +++ b/include/scsi/fc/fc_ms.h @@ -1,17 +1,6 @@ -/* * Copyright(c) 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. +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2011 Intel Corporation. All rights reserved. * * Maintained at www.Open-FCoE.org */ diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 2109844be53d..76cb9192319a 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * 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 */ From 2626b08f396050e492a64f17ea2fbed4babf4b5a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:06 -0400 Subject: [PATCH 013/185] scsi: libfcoe: switch to SPDX tags Use the the GPLv2 SPDX tag instead of verbose boilerplate text. [mkp: fixed comment syntax on *.c] Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/fcoe/fcoe.c | 14 +------------- drivers/scsi/fcoe/fcoe.h | 14 +------------- drivers/scsi/fcoe/fcoe_ctlr.c | 14 +------------- drivers/scsi/fcoe/fcoe_sysfs.c | 14 +------------- drivers/scsi/fcoe/fcoe_transport.c | 14 +------------- include/scsi/libfcoe.h | 14 +------------- 6 files changed, 6 insertions(+), 78 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 8ba8862d3292..2c773cf34652 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * 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..15ee5a83ec04 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * 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..0d7770d07405 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 /* * 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..cd7c875d02ad 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 /* * 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..3d7b2d2eb43f 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 /* * 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/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index bb8092fa1e36..ecf3e5978166 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved. * 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 */ From 2d1fcb6009f459c45b661a6f7cc87f99467c8c33 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:07 -0400 Subject: [PATCH 014/185] scsi: libiscsi: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libiscsi.c | 15 +-------------- drivers/scsi/libiscsi_tcp.c | 13 +------------ include/scsi/iscsi_if.h | 13 +------------ include/scsi/iscsi_proto.h | 13 +------------ include/scsi/libiscsi.h | 15 +-------------- include/scsi/libiscsi_tcp.h | 13 +------------ include/scsi/scsi_bsg_iscsi.h | 16 +--------------- 7 files changed, 7 insertions(+), 91 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index e893949a3d11..040b58a3d7d3 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * 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 #include diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index c3fe3f3a78f5..e0255bb2748f 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * 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/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index d66c07077d68..5b8af179b7ac 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * iSCSI User/Kernel Shares (Defines, Constants, Protocol definitions, etc) * * Copyright (C) 2005 Dmitry Yusupov * Copyright (C) 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. - * - * See the file COPYING included with this distribution for more details. */ #ifndef ISCSI_IF_H diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index df156f1d50b2..3e930ab9b859 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * RFC 3720 (iSCSI) protocol data types * * Copyright (C) 2005 Dmitry Yusupov * Copyright (C) 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. - * - * See the file COPYING included with this distribution for more details. */ #ifndef ISCSI_PROTO_H diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index c9bd935f4fd1..7992f6bb2ebc 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * iSCSI lib definitions * @@ -5,20 +6,6 @@ * Copyright (C) 2004 - 2006 Mike Christie * Copyright (C) 2004 - 2005 Dmitry Yusupov * Copyright (C) 2004 - 2005 Alex Aizman - * - * 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 LIBISCSI_H #define LIBISCSI_H diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index 30520d5ee3d1..b7ce80422215 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * iSCSI over TCP/IP Data-Path lib * * Copyright (C) 2008 Mike Christie * Copyright (C) 2008 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. */ #ifndef LIBISCSI_TCP_H diff --git a/include/scsi/scsi_bsg_iscsi.h b/include/scsi/scsi_bsg_iscsi.h index fd5689d4c052..aa76c1e5b36f 100644 --- a/include/scsi/scsi_bsg_iscsi.h +++ b/include/scsi/scsi_bsg_iscsi.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * iSCSI Transport BSG Interface * * Copyright (C) 2009 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 - * */ #ifndef SCSI_BSG_ISCSI_H From 5502239e73e6167fb67ff9efef4677e6dd90fd57 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:08 -0400 Subject: [PATCH 015/185] scsi: libsas: add a SPDX tag to sas_task.c sas_task.c is the only libsas file missing licensing information. Add a GPLv2 tag for the default kernel license. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c index c3b9befad4e6..a46e8e4c0684 100644 --- a/drivers/scsi/libsas/sas_task.c +++ b/drivers/scsi/libsas/sas_task.c @@ -1,4 +1,4 @@ - +// SPDX-License-Identifier: GPL-2.0 #include "sas_internal.h" #include From 4e74166c52a836f05d4bd8270835703908b34d3e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:09 -0400 Subject: [PATCH 016/185] scsi: libsas: switch sas_ata.[ch] to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 1ecca71df8b5..d9131746737e 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+ /* * Support for SATA devices on Serial Attached SCSI (SAS) controllers * * Copyright (C) 2006 IBM Corporation * * Written by: Darrick J. Wong , 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 From 86b89cb0d26c4050a1916094fcd867f34f44af66 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:10 -0400 Subject: [PATCH 017/185] scsi: libsas: switch remaining files to SPDX tags Use the the GPLv2 SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_discover.c | 18 +----------------- drivers/scsi/libsas/sas_event.c | 18 +----------------- drivers/scsi/libsas/sas_expander.c | 16 +--------------- drivers/scsi/libsas/sas_host_smp.c | 5 +---- drivers/scsi/libsas/sas_init.c | 19 +------------------ drivers/scsi/libsas/sas_internal.h | 19 +------------------ drivers/scsi/libsas/sas_phy.c | 18 +----------------- drivers/scsi/libsas/sas_port.c | 18 +----------------- drivers/scsi/libsas/sas_scsi_host.c | 19 +------------------ include/scsi/libsas.h | 19 +------------------ include/scsi/sas.h | 19 +------------------ include/scsi/sas_ata.h | 17 +---------------- 12 files changed, 12 insertions(+), 193 deletions(-) diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 726ada9b8c79..2518cecb7edf 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 - * - * 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 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 - * - * 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 diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 83f2fd70ce76..76ea83ddafa7 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 * * 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 diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index 9ead93df3a6e..55dcc9c934b2 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 /* * Serial Attached SCSI (SAS) Expander discovery and configuration * * Copyright (C) 2007 James E.J. Bottomley * - * - * 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 #include diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 28a460c36c0b..8f2608995726 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 /* * Serial Attached SCSI (SAS) Transport Layer initialization * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov - * - * 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 diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 2cdb981cf476..1bc248a1b4ea 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 */ /* * Serial Attached SCSI (SAS) class internal header file * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov - * - * 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 e030e1452136..2455199e5ffc 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 - * - * 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" diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 38a10478605c..11f028a441dd 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 - * - * 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" diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index b775445892af..602bd1a17a63 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 /* * Serial Attached SCSI (SAS) class SCSI Host glue. * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov - * - * 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 diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index b08febec7895..901355a1bc53 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -1,26 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * SAS host prototypes and structures header file * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov - * - * 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 _LIBSAS_H_ diff --git a/include/scsi/sas.h b/include/scsi/sas.h index 42a84ef42683..ded4d6b7a377 100644 --- a/include/scsi/sas.h +++ b/include/scsi/sas.h @@ -1,26 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * SAS structures and definitions header file * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov - * - * 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_H_ diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index 00f41aeeecf5..9f5ce0a3e63e 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -1,25 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Support for SATA devices on Serial Attached SCSI (SAS) controllers * * Copyright (C) 2006 IBM Corporation * * Written by: Darrick J. Wong , 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 - * */ #ifndef _SAS_ATA_H_ From 5897b844b7f90d0159b878c279e680ca59e0c75e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:11 -0400 Subject: [PATCH 018/185] scsi: sd: add a SPDX tag to sd.c sd.c is the only sd file missing licensing information. Add a GPLv2 tag for the default kernel license. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ebc80354714c..f3564e406160 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * sd.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale From b0edc7fdc65cd0a7eb97aa3e6a8586656fc51997 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:12 -0400 Subject: [PATCH 019/185] scsi: sd: switch remaining files to SPDX tags Use the the GPLv2 SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_dif.c | 16 +--------------- drivers/scsi/sd_zbc.c | 16 +--------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index db72c82486e3..93ac1e4cab73 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * sd_dif.c - SCSI Data Integrity Field * * Copyright (C) 2007, 2008 Oracle Corporation * Written by: Martin K. Petersen - * - * 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 diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index a340af797a85..d5e83cfa4d74 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SCSI Zoned Block commands * @@ -5,21 +6,6 @@ * Written by: Hannes Reinecke * Modified by: Damien Le Moal * Modified by: Shaun Tancheff - * - * 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 From 5ee7e1f1c6c1263f0970462d19a2853ca1bb694d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:13 -0400 Subject: [PATCH 020/185] scsi: ses: switch to SPDX tags Use the the GPLv2 SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/ses.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 0fc39224ce1e..8afea5a1d3f0 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SCSI Enclosure Services * * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** 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 #include From 203cd5591485715e2c715d1ed262615ddcf1db5a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:14 -0400 Subject: [PATCH 021/185] scsi: sg: switch to SPDX tags Use the the GPLv2+ SPDX tag instead of verbose boilerplate text. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d3f15319b9b3..bcdc28e5ede7 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * 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 */ From 95b04a2ff9c7b0804c260bab0f60e561b35a1001 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:15 -0400 Subject: [PATCH 022/185] scsi: sr: add a SPDX tag to sr.c sr.c is the only sr file missing licensing information. Add a GPLv2 tag for the default kernel license. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/sr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index c3f443d5aea8..3642de844677 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * sr.c Copyright (C) 1992 David Giller * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale From 50a1ea5bebbc663be0b794ece96d47aa8d959528 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 May 2019 12:14:16 -0400 Subject: [PATCH 023/185] scsi: st: add a SPDX tag to st.c st.c is the only st file missing licensing information. Add a GPLv2 tag for the default kernel license. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/st.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 3c6a18ad9a87..9c4c710dcccf 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying file Documentation/scsi/st.txt for more information. From f049cf1a7b6737c75884247c3f6383ef104d255a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Apr 2019 14:39:18 -0700 Subject: [PATCH 024/185] scsi: sd: Rely on the driver core for asynchronous probing As explained during the 2018 LSF/MM session about increasing SCSI disk probing concurrency, the problems with the current probing approach are as follows: - The driver core is unaware of asynchronous SCSI LUN probing. wait_for_device_probe() waits for all asynchronous probes except asynchronous SCSI disk probes. - There is unnecessary serialization between sd_probe() and sd_remove(). This can lead to a deadlock. Hence this patch that modifies the sd driver such that it uses the driver core framework for asynchronous probing. The async domain and get_device()/put_device() pairs that became superfluous due to this change are removed. This patch does not affect the time needed for loading the scsi_debug kernel module with parameters delay=0 and max_luns=256. This patch depends on commit ef0ff68351be ("driver core: Probe devices asynchronously instead of the driver") that went upstream in kernel version v5.1-rc1. Cc: Lee Duncan Cc: Hannes Reinecke Cc: Luis Chamberlain Cc: Johannes Thumshirn Cc: Christoph Hellwig Cc: Pavel Machek Cc: Dan Williams Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi.c | 12 +++--------- drivers/scsi/scsi_pm.c | 6 +----- drivers/scsi/scsi_priv.h | 1 - drivers/scsi/sd.c | 12 +++--------- 4 files changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 49821f138ae0..8128165a46fa 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -86,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); @@ -821,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_pm.c b/drivers/scsi/scsi_pm.c index 3a5dfbb81622..cbdf61c1d667 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -176,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/sd.c b/drivers/scsi/sd.c index f3564e406160..2ba7eef4105a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -568,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, @@ -3253,12 +3254,8 @@ 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) +static void sd_probe_part2(struct scsi_disk *sdkp) { - struct scsi_disk *sdkp = data; struct scsi_device *sdp; struct gendisk *gd; u32 index; @@ -3313,7 +3310,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie) sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); scsi_autopm_put_device(sdp); - put_device(&sdkp->dev); } /** @@ -3405,8 +3401,7 @@ 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); + sd_probe_part2(sdkp); return 0; @@ -3442,7 +3437,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); From 82a54da641f3cacfa31db36fc58a5e903f804c22 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Apr 2019 14:39:19 -0700 Subject: [PATCH 025/185] scsi: sd: Inline sd_probe_part2() Make sd_probe() easier to read by inlining sd_probe_part2(). This patch does not change any functionality. [mkp: applied by hand] Cc: Lee Duncan Cc: Hannes Reinecke Cc: Luis Chamberlain Cc: Johannes Thumshirn Cc: Christoph Hellwig Cc: Pavel Machek Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 103 ++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 59 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2ba7eef4105a..b2fef449590f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3254,64 +3254,6 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) return 0; } -static void sd_probe_part2(struct scsi_disk *sdkp) -{ - 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; - 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); -} - /** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once @@ -3401,7 +3343,50 @@ static int sd_probe(struct device *dev) get_device(dev); dev_set_drvdata(dev, sdkp); - sd_probe_part2(sdkp); + 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; From 4e3ea141b5cb79ded7f4a67bb32e5b23a06a784a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 6 May 2019 08:19:15 +0200 Subject: [PATCH 026/185] scsi: osst: kill obsolete driver The osst driver is becoming obsolete, as the manufacturer went out of business ages ago, and the maintainer has no means of testing any improvements anymore. Plus these days flash drives are cheaper and offer a higher capacity. So drop it completely. Cc: Willem Riede Signed-off-by: Hannes Reinece Signed-off-by: Martin K. Petersen --- Documentation/scsi/osst.txt | 218 -- MAINTAINERS | 10 - drivers/scsi/Kconfig | 22 - drivers/scsi/Makefile | 1 - drivers/scsi/osst.c | 6107 ----------------------------------- drivers/scsi/osst.h | 651 ---- drivers/scsi/osst_detect.h | 7 - drivers/scsi/osst_options.h | 107 - drivers/scsi/st.c | 6 +- 9 files changed, 3 insertions(+), 7126 deletions(-) delete mode 100644 Documentation/scsi/osst.txt delete mode 100644 drivers/scsi/osst.c delete mode 100644 drivers/scsi/osst.h delete mode 100644 drivers/scsi/osst_detect.h delete mode 100644 drivers/scsi/osst_options.h diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt deleted file mode 100644 index 00c8ebb2fd18..000000000000 --- a/Documentation/scsi/osst.txt +++ /dev/null @@ -1,218 +0,0 @@ -README file for the osst driver -=============================== -(w) Kurt Garloff 12/2000 - -This file describes the osst driver as of version 0.8.x/0.9.x, the released -version of the osst driver. -It is intended to help advanced users to understand the role of osst and to -get them started using (and maybe debugging) it. -It won't address issues like "How do I compile a kernel?" or "How do I load -a module?", as these are too basic. -Once the OnStream got merged into the official kernel, the distro makers -will provide the OnStream support for those who are not familiar with -hacking their kernels. - - -Purpose -------- -The osst driver was developed, because the standard SCSI tape driver in -Linux, st, does not support the OnStream SC-x0 SCSI tape. The st is not to -blame for that, as the OnStream tape drives do not support the standard SCSI -command set for Serial Access Storage Devices (SASDs), which basically -corresponds to the QIC-157 spec. -Nevertheless, the OnStream tapes are nice pieces of hardware and therefore -the osst driver has been written to make these tape devs supported by Linux. -The driver is free software. It's released under the GNU GPL and planned to -be integrated into the mainstream kernel. - - -Implementation --------------- -The osst is a new high-level SCSI driver, just like st, sr, sd and sg. It -can be compiled into the kernel or loaded as a module. -As it represents a new device, it got assigned a new device node: /dev/osstX -are character devices with major no 206 and minor numbers like the /dev/stX -devices. If those are not present, you may create them by calling -Makedevs.sh as root (see below). -The driver started being a copy of st and as such, the osst devices' -behavior looks very much the same as st to the userspace applications. - - -History -------- -In the first place, osst shared its identity very much with st. That meant -that it used the same kernel structures and the same device node as st. -So you could only have either of them being present in the kernel. This has -been fixed by registering an own device, now. -st and osst can coexist, each only accessing the devices it can support by -themselves. - - -Installation ------------- -osst got integrated into the linux kernel. Select it during kernel -configuration as module or compile statically into the kernel. -Compile your kernel and install the modules. - -Now, your osst driver is inside the kernel or available as a module, -depending on your choice during kernel config. You may still need to create -the device nodes by calling the Makedevs.sh script (see below) manually. - -To load your module, you may use the command -modprobe osst -as root. dmesg should show you, whether your OnStream tapes have been -recognized. - -If you want to have the module autoloaded on access to /dev/osst, you may -add something like -alias char-major-206 osst -to a file under /etc/modprobe.d/ directory. - -You may find it convenient to create a symbolic link -ln -s nosst0 /dev/tape -to make programs assuming a default name of /dev/tape more convenient to -use. - -The device nodes for osst have to be created. Use the Makedevs.sh script -attached to this file. - - -Using it --------- -You may use the OnStream tape driver with your standard backup software, -which may be tar, cpio, amanda, arkeia, BRU, Lone Tar, ... -by specifying /dev/(n)osst0 as the tape device to use or using the above -symlink trick. The IOCTLs to control tape operation are also mostly -supported and you may try the mt (or mt_st) program to jump between -filemarks, eject the tape, ... - -There's one limitation: You need to use a block size of 32kB. - -(This limitation is worked on and will be fixed in version 0.8.8 of - this driver.) - -If you just want to get started with standard software, here is an example -for creating and restoring a full backup: -# Backup -tar cvf - / --exclude /proc | buffer -s 32k -m 24M -B -t -o /dev/nosst0 -# Restore -buffer -s 32k -m 8M -B -t -i /dev/osst0 | tar xvf - -C / - -The buffer command has been used to buffer the data before it goes to the -tape (or the file system) in order to smooth out the data stream and prevent -the tape from needing to stop and rewind. The OnStream does have an internal -buffer and a variable speed which help this, but especially on writing, the -buffering still proves useful in most cases. It also pads the data to -guarantees the block size of 32k. (Otherwise you may pass the -b64 option to -tar.) -Expect something like 1.8MB/s for the SC-x0 drives and 0.9MB/s for the DI-30. -The USB drive will give you about 0.7MB/s. -On a fast machine, you may profit from software data compression (z flag for -tar). - - -USB and IDE ------------ -Via the SCSI emulation layers usb-storage and ide-scsi, you can also use the -osst driver to drive the USB-30 and the DI-30 drives. (Unfortunately, there -is no such layer for the parallel port, otherwise the DP-30 would work as -well.) For the USB support, you need the latest 2.4.0-test kernels and the -latest usb-storage driver from -http://www.linux-usb.org/ -http://sourceforge.net/cvs/?group_id=3581 - -Note that the ide-tape driver as of 1.16f uses a slightly outdated on-tape -format and therefore is not completely interoperable with osst tapes. - -The ADR-x0 line is fully SCSI-2 compliant and is supported by st, not osst. -The on-tape format is supposed to be compatible with the one used by osst. - - -Feedback and updates --------------------- -The driver development is coordinated through a mailing list - -a CVS repository and some web pages. -The tester's pages which contain recent news and updated drivers to download -can be found on -http://sourceforge.net/projects/osst/ - -If you find any problems, please have a look at the tester's page in order -to see whether the problem is already known and solved. Otherwise, please -report it to the mailing list. Your feedback is welcome. (This holds also -for reports of successful usage, of course.) -In case of trouble, please do always provide the following info: -* driver and kernel version used (see syslog) -* driver messages (syslog) -* SCSI config and OnStream Firmware (/proc/scsi/scsi) -* description of error. Is it reproducible? -* software and commands used - -You may subscribe to the mailing list, BTW, it's a majordomo list. - - -Status ------- -0.8.0 was the first widespread BETA release. Since then a lot of reports -have been sent, but mostly reported success or only minor trouble. -All the issues have been addressed. -Check the web pages for more info about the current developments. -0.9.x is the tree for the 2.3/2.4 kernel. - - -Acknowledgments ----------------- -The driver has been started by making a copy of Kai Makisara's st driver. -Most of the development has been done by Willem Riede. The presence of the -userspace program osg (onstreamsg) from Terry Hardie has been rather -helpful. The same holds for Gadi Oxman's ide-tape support for the DI-30. -I did add some patches to those drivers as well and coordinated things a -little bit. -Note that most of them did mostly spend their spare time for the creation of -this driver. -The people from OnStream, especially Jack Bombeeck did support this project -and always tried to answer HW or FW related questions. Furthermore, he -pushed the FW developers to do the right things. -SuSE did support this project by allowing me to work on it during my working -time for them and by integrating the driver into their distro. - -More people did help by sending useful comments. Sorry to those who have -been forgotten. Thanks to all the GNU/FSF and Linux developers who made this -platform such an interesting, nice and stable platform. -Thanks go to those who tested the drivers and did send useful reports. Your -help is needed! - - -Makedevs.sh ------------ -#!/bin/sh -# Script to create OnStream SC-x0 device nodes (major 206) -# Usage: Makedevs.sh [nos [path to dev]] -# $Id: README.osst.kernel,v 1.4 2000/12/20 14:13:15 garloff Exp $ -major=206 -nrs=4 -dir=/dev -test -z "$1" || nrs=$1 -test -z "$2" || dir=$2 -declare -i nr -nr=0 -test -d $dir || mkdir -p $dir -while test $nr -lt $nrs; do - mknod $dir/osst$nr c $major $nr - chown 0.disk $dir/osst$nr; chmod 660 $dir/osst$nr; - mknod $dir/nosst$nr c $major $[nr+128] - chown 0.disk $dir/nosst$nr; chmod 660 $dir/nosst$nr; - mknod $dir/osst${nr}l c $major $[nr+32] - chown 0.disk $dir/osst${nr}l; chmod 660 $dir/osst${nr}l; - mknod $dir/nosst${nr}l c $major $[nr+160] - chown 0.disk $dir/nosst${nr}l; chmod 660 $dir/nosst${nr}l; - mknod $dir/osst${nr}m c $major $[nr+64] - chown 0.disk $dir/osst${nr}m; chmod 660 $dir/osst${nr}m; - mknod $dir/nosst${nr}m c $major $[nr+192] - chown 0.disk $dir/nosst${nr}m; chmod 660 $dir/nosst${nr}m; - mknod $dir/osst${nr}a c $major $[nr+96] - chown 0.disk $dir/osst${nr}a; chmod 660 $dir/osst${nr}a; - mknod $dir/nosst${nr}a c $major $[nr+224] - chown 0.disk $dir/nosst${nr}a; chmod 660 $dir/nosst${nr}a; - let nr+=1 -done diff --git a/MAINTAINERS b/MAINTAINERS index 5cfbea4ce575..adfb7ffb40ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11662,16 +11662,6 @@ S: Maintained F: drivers/mtd/nand/onenand/ F: include/linux/mtd/onenand*.h -ONSTREAM SCSI TAPE DRIVER -M: Willem Riede -L: osst-users@lists.sourceforge.net -L: linux-scsi@vger.kernel.org -S: Maintained -F: Documentation/scsi/osst.txt -F: drivers/scsi/osst.* -F: drivers/scsi/osst_*.h -F: drivers/scsi/st.h - OP-TEE DRIVER M: Jens Wiklander S: Maintained diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d528018e6fa8..d81edb6ae9e3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -98,28 +98,6 @@ config CHR_DEV_ST To compile this driver as a module, choose M here and read . 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 - and - in the kernel source. - More info on the OnStream driver may be found on - - 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 - . The module will be called osst. - config BLK_DEV_SR tristate "SCSI CDROM support" depends on SCSI && BLK_DEV diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 8826111fdf4a..f69ee35af2c8 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -143,7 +143,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/osst.c b/drivers/scsi/osst.c deleted file mode 100644 index 4bad54463eb2..000000000000 --- a/drivers/scsi/osst.c +++ /dev/null @@ -1,6107 +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 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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 -#include -#include -#include -#include -#include -#include - -#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; - /* fall through */ - case 0x70: - s->fixed_format = 1; - s->flags = sense[2] & 0xe0; - break; - case 0x73: - s->deferred = 1; - /* fall through */ - 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; - /* fall through */ - 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_cntfilemark_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_cntfilemark_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; ifilemark_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 */ - /* fall through */ - 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 */ - /* fall through */ - 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= 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; - } - /* fall through */ - 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 -#include -#include - -/* 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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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 " -#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/st.c b/drivers/scsi/st.c index 9c4c710dcccf..b9e7b291c129 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -228,7 +228,6 @@ static DEFINE_IDR(st_index_idr); -#include "osst_detect.h" #ifndef SIGS_FROM_OSST #define SIGS_FROM_OSST \ {"OnStream", "SC-", "", "osst"}, \ @@ -4267,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; } From a68fdb3aed541808ae6b1078ff840a4d9281731b Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:00 -0500 Subject: [PATCH 027/185] scsi: hpsa: correct simple mode Correct issue with hpsa_simple_mode module parameter. Driver was hanging due to incorrect interrupt setup. Reviewed-by: Justin Lindley Reviewed-by: Dave Carroll Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1bef1da273c2..54b0e3dc2861 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5526,6 +5526,9 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (!dev) return SCSI_MLQUEUE_HOST_BUSY; + if (hpsa_simple_mode) + return IO_ACCEL_INELIGIBLE; + cmd->host_scribble = (unsigned char *) c; if (dev->offload_enabled) { @@ -7978,10 +7981,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; } @@ -8000,6 +8008,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 @@ -8035,14 +8047,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]); @@ -8050,7 +8062,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; } From 0119208885b3faf2459de6d3fcc6d090580b906f Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:07 -0500 Subject: [PATCH 028/185] scsi: hpsa: use local workqueues instead of system workqueues Avoid system stalls by switching to local workqueue. Reviewed-by: Justin Lindley Reviewed-by: David Carroll Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 22 +++++++++++++++++++--- drivers/scsi/hpsa.h | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 54b0e3dc2861..61365fc87786 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8128,6 +8128,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 */ } @@ -8463,8 +8468,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); } @@ -8509,7 +8514,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); } @@ -8677,6 +8682,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 @@ -8806,6 +8817,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; } @@ -8953,6 +8968,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..7aa7378f70dd 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -300,6 +300,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; From 4770e68d162634b2134741d08c49185f858c90ee Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:13 -0500 Subject: [PATCH 029/185] scsi: hpsa: check for tag collision Correct rare multipath issue where a device is deleted with an outstanding cmd which results in a tag collision. The cmd eventually completes. If a collision is detected wait until the command slot is cleared. Reviewed-by: Justin Lindley Reviewed-by: David Carroll Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 21 ++++++++++++++------- drivers/scsi/hpsa.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 61365fc87786..283fd603624b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5635,6 +5635,8 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } c = cmd_tagged_alloc(h, cmd); + if (c == NULL) + return SCSI_MLQUEUE_DEVICE_BUSY; /* * Call alternate submit routine for I/O accelerated commands. @@ -6041,7 +6043,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 @@ -6049,14 +6050,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; } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7aa7378f70dd..75210de71917 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -174,6 +174,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 From b443d3eab600b86025ee338669c9ddd399167a4b Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:20 -0500 Subject: [PATCH 030/185] scsi: hpsa: wait longer for ptraid commands Wait longer for outstanding commands before removing a multipath device. Increase the timeout value for ptraid commands. Reviewed-by: Justin Lindley Reviewed-by: David Carroll Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 283fd603624b..df447f1d6311 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -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"); @@ -1842,25 +1844,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 +2141,15 @@ static int hpsa_slave_configure(struct scsi_device *sdev) sdev->no_uld_attach = !sd || !sd->expose_device; if (sd) { - if (sd->external) + 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; From 9e33f0d5788fe4aaa42b1abf6536d046c724a8cd Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:26 -0500 Subject: [PATCH 031/185] scsi: hpsa: do-not-complete-cmds-for-deleted-devices Close up a rare multipath issue. Close up small hole where a command completes after a device has been removed from SML and before the device is re-added. - Mark device as removed in slave_destroy - Do not complete commands for deleted devices Reviewed-by: Justin Lindley Reviewed-by: David Carroll Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 14 +++++++++++++- drivers/scsi/hpsa.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index df447f1d6311..42d51951b61a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2141,6 +2141,7 @@ static int hpsa_slave_configure(struct scsi_device *sdev) sdev->no_uld_attach = !sd || !sd->expose_device; if (sd) { + sd->was_removed = 0; if (sd->external) { queue_depth = EXTERNAL_QD; sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT; @@ -2160,7 +2161,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) @@ -2588,6 +2594,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) { diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 75210de71917..a013c16af5f1 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; From c5dfd106414f3e038fee5c6f0800fd55ed07b41d Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:33 -0500 Subject: [PATCH 032/185] scsi: hpsa: correct device resets Correct a race condition that occurs between the reset handler and the completion handler. There are times when the wait_event condition is never met due to this race condition and the reset never completes. The reset_pending field is NULL initially. t Reset Handler Thread Completion Thread -- -------------------- ----------------- t1 if (c->reset_pending) t2 c->reset_pending = dev; if (atomic_dev_and_test(counter)) t3 atomic_inc(counter) wait_up_all(event_sync_wait_queue) t4 t5 wait_event(...counter == 0) Kernel.org Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=1994350 Bug 199435 - HPSA + P420i resetting logical Direct-Access never complete Reviewed-by: Justin Lindley Reviewed-by: David Carroll Reviewed-by: Scott Teel Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 173 ++++++++++++++++++++-------------------- drivers/scsi/hpsa.h | 3 +- drivers/scsi/hpsa_cmd.h | 2 +- 3 files changed, 88 insertions(+), 90 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 42d51951b61a..b4df2475ce9c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -346,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) @@ -1146,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) { @@ -1169,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); } @@ -2434,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 @@ -2449,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, @@ -2516,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); } @@ -2621,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); @@ -3074,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; @@ -3082,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"); @@ -3164,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 */ @@ -3175,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, @@ -3214,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; @@ -4846,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); } @@ -5031,6 +4991,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; } @@ -5048,6 +5013,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) { @@ -5131,6 +5099,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: @@ -5435,13 +5406,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... */ @@ -5492,6 +5463,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; @@ -5543,8 +5520,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; @@ -5552,6 +5528,9 @@ 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; @@ -5587,8 +5566,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]; @@ -5596,7 +5579,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) { @@ -5612,7 +5595,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 @@ -5631,7 +5614,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; @@ -5653,13 +5635,15 @@ 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; @@ -5671,7 +5655,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) { @@ -5679,7 +5663,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) @@ -5961,6 +5945,7 @@ 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; u8 reset_type; @@ -6028,9 +6013,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 @@ -6044,6 +6039,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; } @@ -6157,6 +6154,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; } @@ -6610,8 +6608,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; @@ -8105,7 +8102,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); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index a013c16af5f1..f8c88fc7b80a 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -76,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; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 21a726e2eec6..2daf08f81d80 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); From 9a14f9b1be7ca55a33e8680918cdcf75ae202be1 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 7 May 2019 13:32:40 -0500 Subject: [PATCH 033/185] scsi: hpsa: update driver version [mkp: wrong baseline, applied by hand] Reviewed-by: Gerry Morong Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b4df2475ce9c..c560a4532733 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-160" +#define HPSA_DRIVER_VERSION "3.4.20-170" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" From ebeb466531154d6238399eb54438235f6fbbd013 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 14 May 2019 19:23:07 +0200 Subject: [PATCH 034/185] scsi: fdomain: Resurrect driver - Core Future Domain TMC-16xx/TMC-3260 SCSI driver. This is the core driver, common for PCI, ISA and PCMCIA cards. Signed-off-by: Ondrej Zary Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 4 + drivers/scsi/Makefile | 1 + drivers/scsi/fdomain.c | 586 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/fdomain.h | 53 ++++ 4 files changed, 644 insertions(+) create mode 100644 drivers/scsi/fdomain.c create mode 100644 drivers/scsi/fdomain.h diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d81edb6ae9e3..213c5df4d591 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -641,6 +641,10 @@ 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_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" depends on PCI && SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index f69ee35af2c8..9fecb50fd213 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -76,6 +76,7 @@ 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_GENERIC_NCR5380) += g_NCR5380.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c new file mode 100644 index 000000000000..19af1ae608df --- /dev/null +++ b/drivers/scsi/fdomain.c @@ -0,0 +1,586 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 0x08 /* Parity enabled, 0x00 = 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 + SCSI_Cntl); + outb(0, fd->base + SCSI_Mode_Cntl); + if (fd->chip == tmc18c50 || fd->chip == tmc18c30) + /* Clear forced intr. */ + outb(0x21 | PARITY_MASK, fd->base + TMC_Cntl); + else + outb(0x01 | PARITY_MASK, fd->base + TMC_Cntl); +} + +static enum chip_type fdomain_identify(int port) +{ + u16 id = inb(port + LSB_ID_Code) | inb(port + MSB_ID_Code) << 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(0x80, port + IO_Control); + if ((inb(port + Configuration2) & 0x80) == 0x80) { + outb(0x00, port + IO_Control); + if ((inb(port + Configuration2) & 0x80) == 0x00) + 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 + Write_Loopback); + if (inb(base + Read_Loopback) != i) + return 1; + } + + return 0; +} + +static void fdomain_reset(int base) +{ + outb(1, base + SCSI_Cntl); + mdelay(20); + outb(0, base + SCSI_Cntl); + mdelay(1150); + outb(0, base + SCSI_Mode_Cntl); + outb(PARITY_MASK, base + TMC_Cntl); +} + +static int fdomain_select(struct Scsi_Host *sh, int target) +{ + int status; + unsigned long timeout; + struct fdomain *fd = shost_priv(sh); + + outb(0x82, fd->base + SCSI_Cntl); /* Bus Enable + Select */ + outb(BIT(sh->this_id) | BIT(target), fd->base + SCSI_Data_NoACK); + + /* Stop arbitration and enable parity */ + outb(PARITY_MASK, fd->base + TMC_Cntl); + + timeout = 350; /* 350 msec */ + + do { + status = inb(fd->base + SCSI_Status); /* Read adapter status */ + if (status & 1) { /* Busy asserted */ + /* Enable SCSI Bus */ + /* (on error, should make bus idle with 0) */ + outb(0x80, fd->base + SCSI_Cntl); + return 0; + } + mdelay(1); + } while (--timeout); + fdomain_make_bus_idle(fd); + return 1; +} + +static void fdomain_finish_cmd(struct fdomain *fd, int result) +{ + outb(0x00, fd->base + Interrupt_Cntl); + 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 + FIFO_Data_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 + Read_FIFO); + if (len > 1) + insw(fd->base + Read_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 + FIFO_Data_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 + Write_FIFO); + if (len > 1) + outsw(fd->base + Write_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 + TMC_Status); + if (!(status & 0x02)) { + fdomain_finish_cmd(fd, DID_BUS_BUSY << 16); + goto out; + } + cmd->SCp.phase = in_selection; + + outb(0x40 | FIFO_COUNT, fd->base + Interrupt_Cntl); + outb(0x82, fd->base + SCSI_Cntl); /* Bus Enable + Select */ + outb(BIT(cmd->device->host->this_id) | + BIT(scmd_id(cmd)), fd->base + SCSI_Data_NoACK); + /* Stop arbitration and enable parity */ + outb(0x10 | PARITY_MASK, fd->base + TMC_Cntl); + goto out; + } else if (cmd->SCp.phase & in_selection) { + status = inb(fd->base + SCSI_Status); + if (!(status & 0x01)) { + /* 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(0x10 | PARITY_MASK, fd->base + TMC_Cntl); + } + cmd->SCp.phase = in_other; + outb(0x90 | FIFO_COUNT, fd->base + Interrupt_Cntl); + outb(0x80, fd->base + SCSI_Cntl); + goto out; + } + + /* cur_cmd->SCp.phase == in_other: this is the body of the routine */ + status = inb(fd->base + SCSI_Status); + + if (status & 0x10) { /* REQ */ + switch (status & 0x0e) { + case 0x08: /* COMMAND OUT */ + outb(cmd->cmnd[cmd->SCp.sent_command++], + fd->base + Write_SCSI_Data); + break; + case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ + if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { + cmd->SCp.have_data_in = -1; + outb(0xd0 | PARITY_MASK, fd->base + TMC_Cntl); + } + break; + case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ + if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { + cmd->SCp.have_data_in = 1; + outb(0x90 | PARITY_MASK, fd->base + TMC_Cntl); + } + break; + case 0x0c: /* STATUS IN */ + cmd->SCp.Status = inb(fd->base + Read_SCSI_Data); + break; + case 0x0a: /* MESSAGE OUT */ + outb(MESSAGE_REJECT, fd->base + Write_SCSI_Data); + break; + case 0x0e: /* MESSAGE IN */ + cmd->SCp.Message = inb(fd->base + Read_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(0xd0 | PARITY_MASK, fd->base + TMC_Cntl); + } else { + cmd->SCp.have_data_in = 1; + outb(0x90 | PARITY_MASK, fd->base + TMC_Cntl); + } + } + + 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(0xd0 | FIFO_COUNT, fd->base + Interrupt_Cntl); + outb(0x00, fd->base + SCSI_Cntl); + } else + outb(0x90 | FIFO_COUNT, fd->base + Interrupt_Cntl); + } +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 + TMC_Status) & 0x01) == 0) + return IRQ_NONE; + + outb(0x00, fd->base + Interrupt_Cntl); + + /* 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(0x00, fd->base + Interrupt_Cntl); + outb(0x00, fd->base + SCSI_Cntl); /* Disable data drivers */ + outb(BIT(cmd->device->host->this_id), + fd->base + SCSI_Data_NoACK); /* Set our id bit */ + outb(0x20, fd->base + Interrupt_Cntl); + outb(0x14 | PARITY_MASK, fd->base + TMC_Cntl); /* Start arbitration */ + + 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" + }; + + 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 (request_irq(irq, fdomain_irq, dev_is_pci(dev) ? IRQF_SHARED : 0, + "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..fabb2e49461f --- /dev/null +++ b/drivers/scsi/fdomain.h @@ -0,0 +1,53 @@ +/* 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, +}; + +enum in_port_type { + Read_SCSI_Data = 0, + SCSI_Status = 1, + TMC_Status = 2, + FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ + Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ + LSB_ID_Code = 5, + MSB_ID_Code = 6, + Read_Loopback = 7, + SCSI_Data_NoACK = 8, + Interrupt_Status = 9, + Configuration1 = 10, + Configuration2 = 11, /* tmc18c50/tmc18c30 only */ + Read_FIFO = 12, + FIFO_Data_Count = 14 +}; + +enum out_port_type { + Write_SCSI_Data = 0, + SCSI_Cntl = 1, + Interrupt_Cntl = 2, + SCSI_Mode_Cntl = 3, + TMC_Cntl = 4, + Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ + Write_Loopback = 7, + IO_Control = 11, /* tmc18c30 only */ + Write_FIFO = 12 +}; + +#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); From 68046d5003e7b7b4083cdf5dfc2823b7bb0e40ea Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 14 May 2019 19:23:08 +0200 Subject: [PATCH 035/185] scsi: fdomain: Resurrect driver - PCI support Future Domain TMC-3260/AHA-2920A PCI card support. Tested on Adaptec AHA-2920A PCI card. Signed-off-by: Ondrej Zary Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 17 ++++++++++ drivers/scsi/Makefile | 1 + drivers/scsi/fdomain_pci.c | 68 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 drivers/scsi/fdomain_pci.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 213c5df4d591..b66c624affb0 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -645,6 +645,23 @@ 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_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" depends on PCI && SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 9fecb50fd213..f2cea7032419 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -77,6 +77,7 @@ 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_GENERIC_NCR5380) += g_NCR5380.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o 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 +#include +#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"); From e5207cf021df382fe1936f2314ab19e390026a06 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 14 May 2019 19:23:09 +0200 Subject: [PATCH 036/185] scsi: fdomain: Resurrect driver - ISA support Future Domain 16xx ISA SCSI support card support. Tested on IBM 92F0330 card (18C50 chip) with v1.00 BIOS. Signed-off-by: Ondrej Zary Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 14 +++ drivers/scsi/Makefile | 1 + drivers/scsi/fdomain_isa.c | 222 +++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/scsi/fdomain_isa.c diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index b66c624affb0..e365787bf698 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -662,6 +662,20 @@ config SCSI_FDOMAIN_PCI 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 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index f2cea7032419..aeda53901064 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -78,6 +78,7 @@ 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 diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c new file mode 100644 index 000000000000..bca5d56f12aa --- /dev/null +++ b/drivers/scsi/fdomain_isa.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#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 + Configuration1) & 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] + Configuration1) & 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"); From 4a0bcf362d4a55810812030eed89068d7c904870 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:30 -0700 Subject: [PATCH 037/185] scsi: megaraid_sas: Remove unused variable target_index No functional change. Remove set but unused variable in megasas_set_static_target_properties. Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 473a120eb75d..e37b8e5434b2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1930,7 +1930,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; @@ -1947,8 +1946,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; From f10fb8523aeebb99c03bac1f17cb48d0179312d5 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:32 -0700 Subject: [PATCH 038/185] scsi: megaraid_sas: fw_reset_no_pci_access required for MFI adapters only fw_reset_no_pci_access is only applicable for MFI controllers and is not used for Fusion controllers. For all Fusion controllers, driver can check reset adapter bit in status register before performing a chip reset without setting "fw_reset_no_pci_access". Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index e37b8e5434b2..63b31082d985 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5488,7 +5488,6 @@ static int megasas_init_fw(struct megasas_instance *instance) int i, j, loop, fw_msix_count = 0; struct IOV_111 *iovPtr; struct fusion_context *fusion; - bool do_adp_reset = true; fusion = instance->ctrl_context; @@ -5535,13 +5534,18 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (megasas_transition_to_ready(instance, 0)) { - if (instance->adapter_type >= INVADER_SERIES) { + 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) { + instance->instancet->adp_reset + (instance, instance->reg_set); + if (megasas_transition_to_ready(instance, 0)) + 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); @@ -5555,8 +5559,6 @@ static int megasas_init_fw(struct megasas_instance *instance) if (megasas_transition_to_ready(instance, 0)) goto fail_ready_state; - } else { - goto fail_ready_state; } } From 44e8d6930ff67ce5e72a6a81c2a578c801eb2e39 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:33 -0700 Subject: [PATCH 039/185] scsi: megaraid_sas: Rework code around controller reset No functional change. This patch reworks code around controller reset path which gets rid of a couple of goto labels. This is in preparation for the next patch which adds PCI config space access locking while controller reset is in progress. Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_fusion.c | 23 +++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 6fd57f7f0b1e..902b11b97999 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1571,6 +1571,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 diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 6129399c1942..7ef768dce944 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -4567,6 +4567,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) 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; @@ -4685,34 +4687,30 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) /* 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++) { + for (i = 0; i < max_reset_tries; i++) { - if (instance->instancet->adp_reset + if (do_adp_reset && + instance->instancet->adp_reset (instance, instance->reg_set)) 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)) { @@ -4798,7 +4796,6 @@ 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); From 78409d4b47b83d81d29450ef890e07d9ce629fdd Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:34 -0700 Subject: [PATCH 040/185] scsi: megaraid_sas: Block PCI config space access from userspace during OCR While an online controller reset(OCR) is in progress, there is short duration where all access to controller's PCI config space from the host needs to be blocked. This is due to a hardware limitation of MegaRAID controllers. With this patch, driver will block all access to controller's config space from userland applications by calling pci_cfg_access_lock() while OCR is in progress and unlocking after controller comes back to ready state. Added helper function which locks the config space before initiating OCR and wait for controller to become READY. Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 3 + drivers/scsi/megaraid/megaraid_sas_base.c | 15 +++-- drivers/scsi/megaraid/megaraid_sas_fusion.c | 66 +++++++++++++++++++-- 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 902b11b97999..990ee23d7bc2 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2636,4 +2636,7 @@ 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); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 63b31082d985..34abd5194b0b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5534,13 +5534,15 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (megasas_transition_to_ready(instance, 0)) { + 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); if (status_reg & MFI_RESET_ADAPTER) { - instance->instancet->adp_reset - (instance, instance->reg_set); - if (megasas_transition_to_ready(instance, 0)) + if (megasas_adp_reset_wait_for_ready + (instance, true, 0) == FAILED) goto fail_ready_state; } else { goto fail_ready_state; @@ -5550,9 +5552,6 @@ static int megasas_init_fw(struct megasas_instance *instance) 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); @@ -5560,6 +5559,10 @@ static int megasas_init_fw(struct megasas_instance *instance) if (megasas_transition_to_ready(instance, 0)) goto fail_ready_state; } + + dev_info(&instance->pdev->dev, + "FW restarted successfully from %s!\n", + __func__); } megasas_init_ctrl_params(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 7ef768dce944..5dc324ca4090 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -98,6 +98,62 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance); 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_LOGS) + 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_LOGS) + 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 @@ -4693,10 +4749,12 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) /* Now try to reset the chip */ for (i = 0; i < max_reset_tries; i++) { - - if (do_adp_reset && - instance->instancet->adp_reset - (instance, instance->reg_set)) + /* + * 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; /* Wait for FW to become ready */ From 62a04f81e6133c8eaa5e93e15eab1ad2511a45db Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:35 -0700 Subject: [PATCH 041/185] scsi: megaraid_sas: IRQ poll to avoid CPU hard lockups Issue Description: We have seen cpu lock up issues from field if system has a large (more than 96) logical cpu count. SAS3.0 controller (Invader series) supports max 96 MSI-X vector and SAS3.5 product (Ventura) supports max 128 MSI-X vectors. This may be a generic issue (if PCI device support completion on multiple reply queues). Let me explain it w.r.t megaraid_sas supported h/w just to simplify the problem and possible changes to handle such issues. MegaRAID controller supports multiple reply queues in completion path. Driver creates MSI-X vectors for controller as "minimum of (FW supported Reply queues, Logical CPUs)". If submitter is not interrupted via completion on same CPU, there is a loop in the IO path. This behavior can cause hard/soft CPU lockups, IO timeout, system sluggish etc. Example - one CPU (e.g. CPU A) is busy submitting the IOs and another CPU (e.g. CPU B) is busy with processing the corresponding IO's reply descriptors from reply descriptor queue upon receiving the interrupts from HBA. If CPU A is continuously pumping the IOs then always CPU B (which is executing the ISR) will see the valid reply descriptors in the reply descriptor queue and it will be continuously processing those reply descriptor in a loop without quitting the ISR handler. megaraid_sas driver will exit ISR handler if it finds unused reply descriptor in the reply descriptor queue. Since CPU A will be continuously sending the IOs, CPU B may always see a valid reply descriptor (posted by HBA Firmware after processing the IO) in the reply descriptor queue. In worst case, driver will not quit from this loop in the ISR handler. Eventually, CPU lockup will be detected by watchdog. Above mentioned behavior is not common if "rq_affinity" set to 2 or affinity_hint is honored by irqbalancer as "exact". If rq_affinity is set to 2, submitter will be always interrupted via completion on same CPU. If irqbalancer is using "exact" policy, interrupt will be delivered to submitter CPU. Problem statement: If CPU count to MSI-X vectors (reply descriptor Queues) count ratio is not 1:1, we still have exposure of issue explained above and for that we don't have any solution. Exposure of soft/hard lockup is seen if CPU count is more than MSI-X supported by device. If CPUs count to MSI-X vectors count ratio is not 1:1, (Other way, if CPU counts to MSI-X vector count ratio is something like X:1, where X > 1) then 'exact' irqbalance policy OR rq_affinity = 2 won't help to avoid CPU hard/soft lockups. There won't be any one to one mapping between CPU to MSI-X vector instead one MSI-X interrupt (or reply descriptor queue) is shared with group/set of CPUs and there is a possibility of having a loop in the IO path within that CPU group and may observe lockups. For example: Consider a system having two NUMA nodes and each node having four logical CPUs and also consider that number of MSI-X vectors enabled on the HBA is two, then CPUs count to MSI-X vector count ratio as 4:1. e.g. MSI-X vector 0 is affinity to CPU 0, CPU 1, CPU 2 & CPU 3 of NUMA node 0 and MSI-X vector 1 is affinity to CPU 4, CPU 5, CPU 6 & CPU 7 of NUMA node 1. numactl --hardware available: 2 nodes (0-1) node 0 cpus: 0 1 2 3 --> MSI-X 0 node 0 size: 65536 MB node 0 free: 63176 MB node 1 cpus: 4 5 6 7 --> MSI-X 1 node 1 size: 65536 MB node 1 free: 63176 MB Assume that user started an application which uses all the CPUs of NUMA node 0 for issuing the IOs. Only one CPU from affinity list (it can be any cpu since this behavior depends upon irqbalance) CPU0 will receive the interrupts from MSI-X 0 for all the IOs. Eventually, CPU 0 IO submission percentage will be decreasing and ISR processing percentage will be increasing as it is more busy with processing the interrupts. Gradually IO submission percentage on CPU 0 will be zero and it's ISR processing percentage will be 100% as IO loop has already formed within the NUMA node 0, i.e. CPU 1, CPU 2 & CPU 3 will be continuously busy with submitting the heavy IOs and only CPU 0 is busy in the ISR path as it always find the valid reply descriptor in the reply descriptor queue. Eventually, we will observe the hard lockup here. Chances of occurring of hard/soft lockups are directly proportional to value of X. If value of X is high, then chances of observing CPU lockups is high. Solution: Use IRQ poll interface defined in "irq_poll.c". megaraid_sas driver will execute ISR routine in softirq context and it will always quit the loop based on budget provided in IRQ poll interface. Driver will switch to IRQ poll only when more than a threshold number of reply descriptors are handled in one ISR. Currently threshold is set as 1/4th of HBA queue depth. In these scenarios (i.e. where CPUs count to MSI-X vectors count ratio is X:1 (where X > 1)), IRQ poll interface will avoid CPU hard lockups due to voluntary exit from the reply queue processing based on budget. Note - Only one MSI-X vector is busy doing processing. Select CONFIG_IRQ_POLL from driver Kconfig for driver compilation. Signed-off-by: Kashyap Desai Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/Kconfig.megaraid | 1 + drivers/scsi/megaraid/megaraid_sas.h | 5 + drivers/scsi/megaraid/megaraid_sas_base.c | 36 ++++++ drivers/scsi/megaraid/megaraid_sas_fp.c | 1 + drivers/scsi/megaraid/megaraid_sas_fusion.c | 122 +++++++++++++++----- drivers/scsi/megaraid/megaraid_sas_fusion.h | 1 - 6 files changed, 136 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid index 17419e30ffc8..1fa9d095ae36 100644 --- a/drivers/scsi/megaraid/Kconfig.megaraid +++ b/drivers/scsi/megaraid/Kconfig.megaraid @@ -78,6 +78,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/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 990ee23d7bc2..8d6a9c511455 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2173,6 +2173,9 @@ 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; }; struct MR_DRV_SYSTEM_INFO { @@ -2303,6 +2306,7 @@ 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; @@ -2639,4 +2643,5 @@ void megasas_set_dma_settings(struct megasas_instance *instance, 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); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 34abd5194b0b..ec1259f69683 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -5271,6 +5272,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 @@ -5349,6 +5369,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++) { @@ -5721,6 +5751,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"); @@ -7185,6 +7218,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)) diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 87c2c0472c8f..9ac357619b28 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 5dc324ca4090..5fdba1556039 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -1788,6 +1789,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)) @@ -3421,7 +3423,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; @@ -3554,7 +3557,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], @@ -3564,23 +3567,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; + disable_irq_nosync(irq_context->os_irq); + 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); + } } /** @@ -3592,11 +3618,46 @@ 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; + + 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; } /** @@ -3619,7 +3680,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); } /** @@ -3646,7 +3707,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; } /** @@ -4333,6 +4395,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; } @@ -4346,6 +4409,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: @@ -4734,10 +4798,7 @@ 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 */ @@ -4775,9 +4836,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) 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); @@ -4806,7 +4865,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) 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)) @@ -4857,9 +4916,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) /* 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) { @@ -4867,8 +4924,15 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) } 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..160ac16941fe 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -100,7 +100,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 From 1d15d9098ad12b0021ac5a6b851f26d1ab021e5a Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:36 -0700 Subject: [PATCH 042/185] scsi: megaraid_sas: Load balance completions across all MSI-X Driver will use "reply descriptor post queues" in round robin fashion when the combined MSI-X mode is not enabled. With this IO completions are distributed and load balanced across all the available reply descriptor post queues equally. This is enabled only if combined MSI-X mode is not enabled in firmware. This improves performance and also fixes soft lockups. When load balancing is enabled, IRQ affinity from driver needs to be disabled. Signed-off-by: Kashyap Desai Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 3 +++ drivers/scsi/megaraid/megaraid_sas_base.c | 22 +++++++++++++++++---- drivers/scsi/megaraid/megaraid_sas_fusion.c | 18 +++++++++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 8d6a9c511455..6be748f302cf 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2262,6 +2262,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; @@ -2279,6 +2280,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; @@ -2316,6 +2318,7 @@ struct megasas_instance { atomic_t sge_holes_type1; atomic_t sge_holes_type2; atomic_t sge_holes_type3; + atomic64_t total_io_count; struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ec1259f69683..6d2390bf7271 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5349,6 +5349,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); @@ -5357,6 +5358,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) } } } + return 0; } @@ -5660,6 +5662,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; + + if (!instance->msix_combined) { + instance->msix_load_balance = true; + instance->smp_affinity_enable = false; + } + fw_msix_count = instance->msix_vectors; /* Save 1-15 reply post index address to local memory * Index 0 is already saved from reg offset @@ -5678,17 +5686,20 @@ static int megasas_init_fw(struct megasas_instance *instance) 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) + if (instance->smp_affinity_enable) irq_flags |= PCI_IRQ_AFFINITY; i = pci_alloc_irq_vectors(instance->pdev, 1, instance->msix_vectors, irq_flags); - if (i > 0) + if (i > 0) { instance->msix_vectors = i; - else + } else { instance->msix_vectors = 0; + instance->msix_load_balance = false; + } } /* * MSI-X host index 0 is common for all adapter. @@ -6795,6 +6806,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); @@ -6817,6 +6829,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); @@ -7180,7 +7194,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, diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 5fdba1556039..66306ffb34a5 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2768,8 +2768,13 @@ 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->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. @@ -3082,8 +3087,13 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; - cmd->request_desc->SCSIIO.MSIxIndex = - instance->reply_map[raw_smp_processor_id()]; + 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 */ From 96c9603cf1ed84e9d637b66a79090aab379e5078 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:37 -0700 Subject: [PATCH 043/185] scsi: megaraid_sas: Enhance prints in OCR and TM path This patch enhances the existing debug prints in reset and task management path. These debug prints in adapter reset path helps with debugging issues related to IO timeouts that are seen frequently in the field. Add additional debug prints to dump the pending command frames before initiating an adapter reset. Also, print FastPath IOs that are outstanding. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 4 +- drivers/scsi/megaraid/megaraid_sas_base.c | 69 ++++++++++++++++----- drivers/scsi/megaraid/megaraid_sas_fusion.c | 44 +++++++------ 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 6be748f302cf..27980d68cf1b 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1495,7 +1495,8 @@ 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 SCAN_PD_CHANNEL 0x1 #define SCAN_VD_CHANNEL 0x2 @@ -2647,4 +2648,5 @@ 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 6d2390bf7271..9712afa96963 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -55,6 +55,7 @@ #include #include #include +#include #include "megaraid_sas_fusion.h" #include "megaraid_sas.h" @@ -2832,23 +2833,63 @@ 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 provide hexdump + * @ptr: Pointer starting which memory should be dumped + * @size: Size of memory to be dumped */ -static inline void -megasas_dump_frame(void *mpi_request, int sz) +inline void +megasas_dump(void *ptr, int sz) { int i; - __le32 *mfp = (__le32 *)mpi_request; + __le32 *loc = (__le32 *)ptr; - 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])); + printk("%08x ", le32_to_cpu(loc[i])); } printk("\n"); } +/** + * 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); + + 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); + printk(KERN_INFO "Chain frame:\n"); + megasas_dump(cmd->sg_frame, + instance->max_chain_frame_sz); + } + +} + /** * megasas_reset_bus_host - Bus & host reset handler entry point */ @@ -2860,24 +2901,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); } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 66306ffb34a5..7ee9d128ae43 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -122,7 +122,7 @@ megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, * Block access to PCI config space from userspace * when diag reset is initiated from driver */ - if (megasas_dbg_lvl & OCR_LOGS) + if (megasas_dbg_lvl & OCR_DEBUG) dev_info(&instance->pdev->dev, "Block access to PCI config space %s %d\n", __func__, __LINE__); @@ -145,7 +145,7 @@ megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, ret = SUCCESS; out: - if (megasas_dbg_lvl & OCR_LOGS) + if (megasas_dbg_lvl & OCR_DEBUG) dev_info(&instance->pdev->dev, "Unlock access to PCI config space %s %d\n", __func__, __LINE__); @@ -4518,9 +4518,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); @@ -4563,7 +4560,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; @@ -4574,9 +4571,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; } @@ -4599,9 +4599,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); @@ -4610,8 +4607,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; @@ -4634,7 +4631,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, @@ -4643,10 +4640,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; } @@ -4691,7 +4688,7 @@ 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; @@ -4765,7 +4762,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 */ @@ -4778,13 +4775,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); @@ -4797,6 +4798,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); From 2ce435087902d42fa33d0032143868ceb42d9fb6 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:38 -0700 Subject: [PATCH 044/185] scsi: megaraid_sas: Enhance internal DCMD timeout prints Add prints to identify the internal DCMD opcode that has timed out. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 9712afa96963..d3f4b48be1cd 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1112,8 +1112,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 @@ -1142,6 +1143,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); @@ -1177,8 +1179,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 From 4fe55035f30fb38bfb898c974f603943cdfe390a Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:39 -0700 Subject: [PATCH 045/185] scsi: megaraid_sas: Add formatting option for megasas_dump Add option to format the buffer that is being dumped. Currently, the IO frame and chain frame dumped in the syslog is getting split across multiple lines based on the formatting. Fix this by using KERN_CONT in printk. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 30 ++++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d3f4b48be1cd..7d7cf8b82e9e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2837,22 +2837,28 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) } /** - * megasas_dump - This function will provide hexdump - * @ptr: Pointer starting which memory should be dumped - * @size: Size of memory to be dumped + * 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. */ inline void -megasas_dump(void *ptr, int sz) +megasas_dump(void *buf, int sz, int format) { int i; - __le32 *loc = (__le32 *)ptr; + __le32 *buf_loc = (__le32 *)buf; - for (i = 0; i < sz / sizeof(__le32); i++) { - if (i && ((i % 8) == 0)) - printk("\n\t"); - printk("%08x ", le32_to_cpu(loc[i])); + 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("\n"); + printk(KERN_CONT "\n"); } /** @@ -2886,10 +2892,10 @@ megasas_dump_fusion_io(struct scsi_cmnd *scmd) printk(KERN_INFO "IO request frame:\n"); megasas_dump(cmd->io_request, - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE); + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8); printk(KERN_INFO "Chain frame:\n"); megasas_dump(cmd->sg_frame, - instance->max_chain_frame_sz); + instance->max_chain_frame_sz, 8); } } From cfb9a30e5dcacbaf783357f0ef5f7f9adf205d34 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:40 -0700 Subject: [PATCH 046/185] scsi: megaraid_sas: Dump system interface regs from sysfs Add a sysfs interface to dump the controller's system interface registers. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 7d7cf8b82e9e..e9acbe14af17 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2900,6 +2900,29 @@ megasas_dump_fusion_io(struct scsi_cmnd *scmd) } +/* + * 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])); + } + return bytes_wrote; +} + /** * megasas_reset_bus_host - Bus & host reset handler entry point */ @@ -3222,6 +3245,17 @@ megasas_fw_cmds_outstanding_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding)); } +static ssize_t +megasas_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 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, @@ -3234,6 +3268,8 @@ 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 DEVICE_ATTR(dump_system_regs, S_IRUGO, + megasas_dump_system_regs_show, NULL); struct device_attribute *megaraid_host_attrs[] = { &dev_attr_fw_crash_buffer_size, @@ -3242,6 +3278,7 @@ struct device_attribute *megaraid_host_attrs[] = { &dev_attr_page_size, &dev_attr_ldio_outstanding, &dev_attr_fw_cmds_outstanding, + &dev_attr_dump_system_regs, NULL, }; From 3d1d9eb7f294ca740b90f6ed4d13f09a7a4e7fcf Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:41 -0700 Subject: [PATCH 047/185] scsi: megaraid_sas: Dump system registers for debugging When controller fails to transition to READY state during driver probe, dump the system interface register set. This will give snapshot of the firmware status for debugging driver load issues. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index e9acbe14af17..fb0ccba97b32 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2861,6 +2861,24 @@ megasas_dump(void *buf, int sz, int format) 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 @@ -3890,8 +3908,11 @@ megasas_transition_to_ready(struct megasas_instance *instance, int 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: /* @@ -3999,6 +4020,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) 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; } @@ -4021,6 +4044,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; } From 9a5987101c15e57720759315e66d4884378f13c3 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:42 -0700 Subject: [PATCH 048/185] scsi: megaraid_sas: Print BAR information from driver Add prints for BAR address information during driver load. This helps in debugging issues with BAR address changing during OS boot. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index fb0ccba97b32..202d5ce60a2c 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5624,6 +5624,7 @@ 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; @@ -5649,6 +5650,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 { From a6024a9e9153d8ff2719724e20f401878e20891d Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:43 -0700 Subject: [PATCH 049/185] scsi: megaraid_sas: Export RAID map id through sysfs Add a sysfs interface to get the raid map index that is being used by driver. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 202d5ce60a2c..ed38cec35604 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3274,6 +3274,18 @@ megasas_dump_system_regs_show(struct device *cdev, return megasas_dump_sys_regs(instance->reg_set, buf); } +static ssize_t +megasas_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(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, @@ -3288,6 +3300,8 @@ static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO, megasas_fw_cmds_outstanding_show, NULL); static DEVICE_ATTR(dump_system_regs, S_IRUGO, megasas_dump_system_regs_show, NULL); +static DEVICE_ATTR(raid_map_id, S_IRUGO, + megasas_raid_map_id_show, NULL); struct device_attribute *megaraid_host_attrs[] = { &dev_attr_fw_crash_buffer_size, @@ -3297,6 +3311,7 @@ struct device_attribute *megaraid_host_attrs[] = { &dev_attr_ldio_outstanding, &dev_attr_fw_cmds_outstanding, &dev_attr_dump_system_regs, + &dev_attr_raid_map_id, NULL, }; From b6661342f26bbeb75948827b9bb0484c19d41865 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:44 -0700 Subject: [PATCH 050/185] scsi: megaraid_sas: Print FW fault information When driver detects a firmware fault during load, dump additional information on fault code and subcode that will help in debugging. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 2 ++ drivers/scsi/megaraid/megaraid_sas_base.c | 5 ++++- drivers/scsi/megaraid/megaraid_sas_fusion.c | 25 ++++++++++++--------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 27980d68cf1b..8df6ef01785e 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -135,6 +135,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 * diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ed38cec35604..fce79f36ace6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3918,7 +3918,10 @@ 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; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 7ee9d128ae43..7ec4920e3618 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3983,7 +3983,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"); @@ -3993,11 +3993,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); @@ -4009,7 +4011,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 = @@ -4028,12 +4030,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" From 223d5818e73065d9076ad6638647dc171135164e Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:45 -0700 Subject: [PATCH 051/185] scsi: megaraid_sas: Print firmware interrupt status Add a print to dump the interrupt status in system log for debugging. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 7ec4920e3618..2edb08247efa 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -202,7 +202,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)); } /** @@ -213,14 +214,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 @@ -4894,9 +4895,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) 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) { From f7331f18001405c0e150a608fd66550e64135a34 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:46 -0700 Subject: [PATCH 052/185] scsi: megaraid_sas: Add prints in suspend and resume path Add prints in resume/suspend path to help in debugging hibernation issues. The print gives an indication when the driver entry points are called. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index fce79f36ace6..415e5d483fb1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -7242,6 +7242,8 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) host = instance->host; 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); @@ -7296,6 +7298,7 @@ megasas_resume(struct pci_dev *pdev) 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 */ From 0a11c0b02a48933d3a21b6608ccb770486fa0181 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:47 -0700 Subject: [PATCH 053/185] scsi: megaraid_sas: Add debug prints for device list Add debug prints related to device list being returned by firmware. The a debug flag to activate these prints. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_base.c | 35 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 8df6ef01785e..840506f2f33c 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1499,6 +1499,7 @@ struct megasas_ctrl_info { /* Driver's internal Logging levels*/ #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 diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 415e5d483fb1..8a3cf9b2dda2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4511,6 +4511,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))) @@ -4526,6 +4529,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++; } @@ -4629,6 +4637,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; @@ -4638,6 +4650,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); } } @@ -4741,6 +4757,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; @@ -4748,6 +4768,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; @@ -4827,6 +4850,10 @@ megasas_host_device_list_query(struct megasas_instance *instance, */ count = le32_to_cpu(ci->count); + 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); @@ -4838,8 +4865,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); } } From ce88418dce0b471491cee63eee628df13fff03ec Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:48 -0700 Subject: [PATCH 054/185] scsi: megaraid_sas: Fix MSI-X vector print Print FW supported MSI-X vector count only if FW supports MSI-X. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 8a3cf9b2dda2..555292e5ff27 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5680,7 +5680,7 @@ static int megasas_init_fw(struct megasas_instance *instance) 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; @@ -5801,7 +5801,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) @@ -5836,7 +5835,6 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->smp_affinity_enable = false; } - fw_msix_count = instance->msix_vectors; /* Save 1-15 reply post index address to local memory * Index 0 is already saved from reg offset * MPI2_REPLY_POST_HOST_INDEX_OFFSET @@ -5849,6 +5847,10 @@ 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); @@ -5891,8 +5893,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()); From ba53572bf02da1836e5780e8c283c8e0cea714e2 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:49 -0700 Subject: [PATCH 055/185] scsi: megaraid_sas: Export RAID map through debugfs Create a debugfs interface for megaraid_sas driver. Provide interface to dump driver RAID map in debugfs. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/Makefile | 2 +- drivers/scsi/megaraid/megaraid_sas.h | 4 + drivers/scsi/megaraid/megaraid_sas_base.c | 14 ++ drivers/scsi/megaraid/megaraid_sas_debugfs.c | 180 +++++++++++++++++++ drivers/scsi/megaraid/megaraid_sas_fusion.h | 5 + 5 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 drivers/scsi/megaraid/megaraid_sas_debugfs.c 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/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 840506f2f33c..56b3204d3fc6 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2390,6 +2390,10 @@ 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; }; struct MR_LD_VF_MAP { diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 555292e5ff27..3a9128ed304d 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -188,6 +188,12 @@ static bool support_nvme_encapsulation; /* 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); @@ -7139,6 +7145,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); @@ -7609,6 +7617,8 @@ skip_firing_dcmds: megasas_free_ctrl_mem(instance); + megasas_destroy_debugfs(instance); + scsi_host_put(host); pci_disable_device(pdev); @@ -8536,6 +8546,8 @@ static int __init megasas_init(void) megasas_mgmt_majorno = rval; + megasas_init_debugfs(); + /* * Register ourselves as PCI hotplug module */ @@ -8595,6 +8607,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; } @@ -8617,6 +8630,7 @@ static void __exit megasas_exit(void) &driver_attr_support_nvme_encapsulation); 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..e52837bb6807 --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c @@ -0,0 +1,180 @@ +/* + * 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 . + * + * Authors: Broadcom Inc. + * Kashyap Desai + * Sumit Saxena + * Shivasharan S + * + * Send feedback to: megaraidlinux.pdl@broadcom.com + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "megaraid_sas_fusion.h" +#include "megaraid_sas.h" + +#ifdef CONFIG_DEBUG_FS +#include + +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_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 160ac16941fe..98738290c533 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -1360,6 +1360,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); From c9ac8e2466fe321b1a13e8ebfbce4d74f31b471b Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Tue, 7 May 2019 10:05:50 -0700 Subject: [PATCH 056/185] scsi: megaraid_sas: Update driver version to 07.708.03.00 Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 56b3204d3fc6..e138d1447e43 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -33,8 +33,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "07.707.51.00-rc1" -#define MEGASAS_RELDATE "February 7, 2019" +#define MEGASAS_VERSION "07.708.03.00-rc1" +#define MEGASAS_RELDATE "March 14, 2019" /* * Device IDs From 2d71dc8eb6e826f42f5dd0c8e005044a65c1da8b Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:51 -0700 Subject: [PATCH 057/185] scsi: lpfc: Fix alloc context on oas lun creations Softlockups are seen in low memory situations. They are due to doing oas_lun allocation with GFP_KERNEL in atomic contexts. Change the calls to oas_lun to indicate atomic context so that GFP_ATOMIC is used. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index ba996fbde89b..3873d5b97bc6 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5741,7 +5741,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; From 32b938656462dd2c4aa1e91e0b48cd114c2d00f7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:52 -0700 Subject: [PATCH 058/185] scsi: lpfc: Fix nvmet target abort cmd matching After receiving an unsolicited ABTS (meaning rxid is 0xFFFF), the driver used the oxid from the initiator to match against a local xri which may have been allocated for the io. The xri would be the rxid - it's an invalid check resulting in the command not being matched or erroneously matched. Change the lookup to use the oxid and the SID to match against received IO's original values. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index d74bfd264495..c9011579aa0f 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1497,6 +1497,7 @@ 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; @@ -1562,6 +1563,7 @@ 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); +#endif } int @@ -1572,19 +1574,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; + uint32_t sid; uint16_t xri; unsigned long iflag = 0; xri = be16_to_cpu(fc_hdr->fh_ox_id); + sid = sli4_sid_from_fc_hdr(fc_hdr); 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 != xri || 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); @@ -1613,7 +1619,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, xri, 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 xid x%x\n", xri); /* Respond with BA_RJT accordingly */ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0); From 4767c58af96e1c6a2dad307c6e5bb75d6c646815 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:53 -0700 Subject: [PATCH 059/185] scsi: lpfc: Correct nvmet buffer free race condition A race condition resulted in receive buffers being placed in the free list twice. Change the locking and handling to check whether the "other" path will be freeing the entry in a later thread and skip it if it is. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index c9011579aa0f..3a11861b7ad6 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -343,16 +343,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; From 2ab70c210664c76b293ba30f46d2831b9960e8f6 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:54 -0700 Subject: [PATCH 060/185] scsi: lpfc: Revise message when stuck due to unresponsive adapter Revise a stalled adapter message to also include the number of jobs that are stalling the thread. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 9d99cb915390..39514d4c279d 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2143,7 +2143,9 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, struct completion *lport_unreg_cmp) { 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 @@ -2153,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; From d74a89aab9be1df8bceb564258305e0f3bf1c471 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:55 -0700 Subject: [PATCH 061/185] scsi: lpfc: Separate CQ processing for nvmet_fc upcalls Currently the driver is notified of new command frame receipt by CQEs. As part of the CQE processing, the driver upcalls the nvmet_fc transport to deliver the command. nvmet_fc, as part of receiving the command builds out a context for it, where one of the first steps is to allocate memory for the io. When running with tests that do large ios (1MB), it was found on some systems, the total number of outstanding I/O's, at 1MB per, completely consumed the system's memory. Thus additional ios were getting blocked in the memory allocator. Given that this blocked the lpfc thread processing CQEs, there were lots of other commands that were received and which are then held up, and given CQEs are serially processed, the aggregate delays for an IO waiting behind the others became cummulative - enough so that the initiator hit timeouts for the ios. The basic fix is to avoid the direct upcall and instead schedule a work item for each io as it is received. This allows the cq processing to complete very quickly, and each io can then run or block on it's own. However, this general solution hurts latency when there are few ios. As such, implemented the fix such that the driver watches how many CQEs it has processed sequentially in one run. As long as the count is below a threshold, the direct nvmet_fc upcall will be made. Only when the count is exceeded will it revert to work scheduling. Given that debug of this showed a surprisingly long delay in cq processing, the io timer stats were updated to better reflect the processing of the different points. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_crtn.h | 3 +- drivers/scsi/lpfc/lpfc_nvmet.c | 67 ++++++++++++++++++++++++---------- drivers/scsi/lpfc/lpfc_sli.c | 22 ++++++----- drivers/scsi/lpfc/lpfc_sli4.h | 2 + 4 files changed, 64 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index e0b14d791b8c..97f0ef236661 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -568,7 +568,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_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 3a11861b7ad6..95386f90a874 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -395,8 +395,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; @@ -1877,6 +1878,10 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) payload = (uint32_t *)(nvmebuf->dbuf.virt); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; +#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 @@ -2015,6 +2020,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 @@ -2027,7 +2034,8 @@ 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; @@ -2136,24 +2144,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); + } } /** @@ -2190,6 +2215,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 @@ -2201,14 +2228,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); } /** diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 2acda188b0dc..946f3024d4db 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13582,14 +13582,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); @@ -13603,6 +13598,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) { @@ -13918,10 +13916,10 @@ 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: @@ -14087,6 +14085,12 @@ 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 " diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 8e4fd1a98023..fbc1f1880d53 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -197,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; From 79d8c4ce01b273348e98335c9a9e405e549a88c6 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:56 -0700 Subject: [PATCH 062/185] scsi: lpfc: Fix nvmet handling of received ABTS for unmapped frames The driver currently is relying on firmware to match ABTSs to existing exchanges. This works fine as long as an exchange has been assigned to the io and work posted to it. However, for unmapped frames (rxid=0xFFFF), the driver has yet to assign an xri. The driver was blindly saying it couldn't match the ABTS and sending the BA_xxx. However, the command frame may have been in queues waiting on xri's before posting to the nvmet_fc layer. When xri's became available, the command frame would still be pushed to the transport and that io would execute, even though the io had been killed by ABTS. The initiator, seeing the io ABTS'd, would reuse the exchange for a different io which would be received on the target and pushed up. If the "zombie" io then came back down and started transmitting, the initiator would match the oxid and accept erroneous data. Bad things happened. Add tracking of active exchanges in the target to allow matching of a received ABTS against active or pending IO requests. If the ABTS is matched to a pending or active IO, the drive initiates cleanup and conditionally notifies the transport. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 + drivers/scsi/lpfc/lpfc_nvmet.c | 234 +++++++++++++++++++++++++++++---- drivers/scsi/lpfc/lpfc_nvmet.h | 1 + drivers/scsi/lpfc/lpfc_sli4.h | 2 + 4 files changed, 214 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index eaaef682de25..70afa585b027 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -6551,6 +6551,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 */ diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 95386f90a874..a943b2a20001 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -220,19 +220,66 @@ lpfc_nvmet_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } +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; +} + +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; +} + 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); @@ -410,9 +457,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); @@ -441,6 +486,9 @@ 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. */ + 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); @@ -708,8 +756,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; @@ -930,7 +980,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; @@ -1030,7 +1080,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", @@ -1043,7 +1093,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; } @@ -1106,6 +1156,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; @@ -1130,7 +1181,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, 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; @@ -1510,6 +1561,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, 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; @@ -1540,7 +1592,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; @@ -1560,7 +1612,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); @@ -1571,6 +1623,32 @@ 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, smp_processor_id(), 0); + + req = &ctxp->ctx.fcp_req; + if (req) + nvmet_fc_rcv_fcp_abort(phba->targetport, req); + } #endif } @@ -1583,18 +1661,18 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; struct nvmefc_tgt_fcp_req *rsp; uint32_t sid; - uint16_t xri; + 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->oxid != xri || ctxp->sid != sid) + if (ctxp->oxid != oxid || ctxp->sid != sid) continue; xri = ctxp->ctxbuf->sglq->sli4_xritag; @@ -1623,11 +1701,92 @@ 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, raw_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 { + 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, 0); + 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 xid 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); @@ -1711,6 +1870,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); @@ -1876,8 +2047,16 @@ 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(); @@ -1931,6 +2110,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) 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", @@ -2122,6 +2302,9 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, 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", @@ -2773,7 +2956,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; } @@ -2782,7 +2965,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, @@ -2857,7 +3040,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; } @@ -2866,7 +3049,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, @@ -3237,7 +3420,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; } @@ -3246,8 +3429,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; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 2f3f603d94c4..8ff67deac10a 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -140,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_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index fbc1f1880d53..12ffe5736921 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -845,6 +845,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; From f6978f4163671ff0ced80ca7423c476627ac99ab Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:57 -0700 Subject: [PATCH 063/185] scsi: lpfc: Revert message logging on unsupported topology Turns out the message change in 12.2.0.1 for unsupported topology makes the linux driver out of sync with other products. Revert the message back to the prior content for product consistency. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e9adb3f1961d..aabd42c4c6f8 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4090,9 +4090,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, } if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && - val != FLAGS_TOPOLOGY_MODE_PT_PT) { + val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3114 Only non-FC-AL mode is supported\n"); + "3114 Loop mode not supported\n"); return -EINVAL; } phba->cfg_topology = val; From f22bfe8d1c900b8ce2105223db69742d8ebc46fe Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:58 -0700 Subject: [PATCH 064/185] scsi: lpfc: Fix PT2PT PLOGI collison stopping discovery Under heavy load the target stops responding, the drivers aborts timeout and we start recovery by logging out of the target, but the target is never logged into again. In a point-to-point scenario, there were battling PLOGI's. When we received a PLOGI request after having sent one, the driver cancels the processing of the original plogi. However, the completion path of the remaining plogi was coded to skip the reg_rpi that should be happening on the 2nd plogi. Correct by adding a simple pt2pt check such that the 2nd plogi isn't skipped and the reg_login occurs. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c8fb0b455f2a..532728ee1f95 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4196,6 +4196,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, From 51d23fb28ccb355ee4d26dedacca24c171c2f664 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:48:59 -0700 Subject: [PATCH 065/185] scsi: lpfc: Prevent 'use after free' memory overwrite in nvmet LS handling Use-after-free memory overwrite detected. Problem reported by Ewan Milne at Red Hat after running lpfc target with additional memory checking enabled. Race condition when lpfc_nvmet_xmt_ls_rsp_cmp frees the ctxp memory in interrupt context before lpfc_nvmet_xmt_ls_rsp clears a field in the ctxp after successfully issuing the wqe. Remove the unnecessary ctxp write after reposting the rq buffer. The ctxp->rqb_buffer field is not checked in LS handling after the wqe is submitted. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reported-by: Ewan Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index a943b2a20001..08c2c4e3515b 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -907,7 +907,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; } From 6594d31bab02e4a1d02355ff2f16a87dfc11b34f Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:00 -0700 Subject: [PATCH 066/185] scsi: lpfc: Cancel queued work for an IO when processing a received ABTS When queued work is executed posting a new command to the transport the driver is reporting a null buffer. The driver had received an ABTS which matched a command that had been scheduled for delivery to the transport. The driver proceeded to cancel the command, but the work item was never cancelled. Fix by cancelling the queued work item. Also turns out the ABTS response was not properly sending a BA_ACC, so set the flag to send the ACC. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 08c2c4e3515b..36e8d842d973 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1766,6 +1766,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, 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); @@ -1777,7 +1778,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); - lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0); + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); return 0; } From b9e5a2d961dbedd7ee293d21f12d6b5d4d4fc35a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:01 -0700 Subject: [PATCH 067/185] scsi: lpfc: Fix hardlockup in scsi_cmd_iocb_cmpl There is a race condition with the abort handler declaring a waitq item on it's stack, followed by a timeout in the abort handler that has it give up on the abort return to its caller. When the io is finally aborted and its completion handler called, it references the waitq element that the abort_handler set up, which is no longer valid resulting in a deadlock. Fix by clearing the waitq reference, under lock, when the abort handler timeout gives up. Have the completion handler validate the waitq before referencing it. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 3873d5b97bc6..5a5a9bbe6023 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -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); @@ -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; From c15e07047e7ad006324d8a8b9d58a86e8f0131fe Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:02 -0700 Subject: [PATCH 068/185] scsi: lpfc: Rework misleading nvme not supported in firmware message The driver unconditionally says fw doesn't support nvme when in truth it was a driver parameter settings that disabled nvme support. Rework the code validating nvme support to accurately report what condition is disabling nvme support. Save state on whether nvme fw supports nvme in case sysfs attributes change dynamically. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 51 ++++++++++++++++++++++++----------- drivers/scsi/lpfc/lpfc_sli4.h | 1 + 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 70afa585b027..1468a4d7c501 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11333,24 +11333,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 = 0; - 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)); + /* Check for firmware nvme support */ + rc = (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; + 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 */ diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 12ffe5736921..8b28a55c73bb 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -514,6 +514,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 From 04d210c98e11d863ebe38a7e482e40fb90d9ad82 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:03 -0700 Subject: [PATCH 069/185] scsi: lpfc: Fix memory leak in abnormal exit path from lpfc_eq_create eq create is leaking mailbox memory if it encounters an error. rework error path to free the memory. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 946f3024d4db..4432060f7315 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -14641,8 +14641,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, @@ -14694,7 +14696,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; } From b8e6f13617db126c8898908e8601f5e4e3b393cf Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:04 -0700 Subject: [PATCH 070/185] scsi: lpfc: Fix incorrect logical link speed on trunks when links down Invalid logical speed is displayed for trunk enabled ports when all ports are down. Also noted that link speed is incorrectly reported for the units when links are up. Current code is returning the logical link speed from the last event from the adapter. In cases where the last link went down, the link speed in the event was not valid - meaning that although the links where down the field had a bogus value. Rework the event handling to qualify the trunk link state before using the event speed data. Also correct units on other areas where the logical link speed was taken from a link event. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_bsg.c | 2 +- drivers/scsi/lpfc/lpfc_init.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index b0202bc0aa62..b7216d694bff 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -5741,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_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1468a4d7c501..73b77aaf7135 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5055,7 +5055,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( @@ -5158,8 +5158,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:" From d9954a2d18c3405bbbe3f15390a9747f66df9f9a Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:05 -0700 Subject: [PATCH 071/185] scsi: lpfc: Fix oops when driver is loaded with 1 interrupt vector The driver was coded expecting enough hardware queues and interrupt vectors such that at least there was one per socket. In the case where there were fewer than sockets, cpus were left unassigned thus null pointers. Rework the affinity mappings. Map settings for the cpu's that are in the irq cpu mask. For each cpu not in the mask, map to another cpu that does have a mask. Choice of the "other" cpu will attempt to map to the same cpu but differing hyperthread, or cpu within in same core, or cpu within same socket, or finally cpu in the base socket. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 27 ++++--- drivers/scsi/lpfc/lpfc_init.c | 143 +++++++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_sli4.h | 4 +- 3 files changed, 155 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index aabd42c4c6f8..58f26e5f3a59 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5236,35 +5236,44 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, 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 += 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 += 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 += 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++; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 73b77aaf7135..021b01561597 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -10653,24 +10653,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) { @@ -10679,13 +10686,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, @@ -10711,6 +10717,12 @@ 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 now we + * are assuming all CPUs using the same EQ will all share + * the same hardware queue. + */ for (idx = 0; idx < phba->cfg_irq_chann; idx++) { maskp = pci_irq_get_affinity(phba->pcidev, idx); if (!maskp) @@ -10728,6 +10740,119 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) cpu, cpup->hdwq, cpup->irq); } } + + /* 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 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->hdwq = new_cpup->hdwq; + 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_ERR, LOG_INIT, + "3337 Set Affinity: CPU %d " + "hdwq %d irq %d from id %d same " + "phys_id (%d)\n", + cpu, cpup->hdwq, 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 " + "hdwq %d irq %d UNASSIGNED\n", + cpu, cpup->hdwq, cpup->irq); + continue; +found_any: + /* We found an available entry, copy the IRQ info */ + cpup->eq = new_cpup->eq; + cpup->hdwq = new_cpup->hdwq; + 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_ERR, LOG_INIT, + "3338 Set Affinity: CPU %d " + "hdwq %d irq %d from id %d (%d/%d)\n", + cpu, cpup->hdwq, cpup->irq, new_cpu, + new_cpup->phys_id, new_cpup->core_id); + } + } return; } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 8b28a55c73bb..69c6dba77dce 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -549,7 +549,9 @@ 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_VECTOR_MAP_EMPTY 0xffff From 657add4e5e15b4872e6a6c2dfca43bff1b0197b4 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:06 -0700 Subject: [PATCH 072/185] scsi: lpfc: Fix poor use of hardware queues if fewer irq vectors While fixing the resources per socket, realized the driver was not using hardware queues (up to 1 per cpu) if there were fewer interrupt vectors. The driver was only using the hardware queue assigned to the cpu with the vector. Rework the affinity map check to use the additional hardware queue elements that had been allocated. If the cpu count exceeds the hardware queue count - share, but choose what is shared with by: hyperthread peer, core peer, socket peer, or finally similar cpu in a different socket. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 3 +- drivers/scsi/lpfc/lpfc_init.c | 321 ++++++++++++++++++++++++---------- drivers/scsi/lpfc/lpfc_sli.c | 42 +++-- drivers/scsi/lpfc/lpfc_sli4.h | 2 + 4 files changed, 255 insertions(+), 113 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 58f26e5f3a59..065c526218b2 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5115,7 +5115,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; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 021b01561597..416f0fb155f5 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -93,7 +93,6 @@ 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 struct scsi_transport_template *lpfc_transport_template = NULL; @@ -1274,8 +1273,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; @@ -8748,8 +8749,10 @@ int lpfc_sli4_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; - int idx, eqidx, cpu; + 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; /* @@ -8834,40 +8837,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++) { - /* determine EQ affinity */ - eqidx = lpfc_find_eq_handle(phba, idx); - cpu = lpfc_find_cpu_handle(phba, eqidx, LPFC_FIND_BY_EQ); - /* - * If there are more Hardware Queues than available - * EQs, 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 */ - 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, 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 */ - qdesc->chann = cpu; - 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++) { @@ -9130,23 +9153,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; + } } /** @@ -9330,10 +9361,13 @@ lpfc_setup_cq_lookup(struct lpfc_hba *phba) 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; @@ -9362,9 +9396,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; @@ -9425,32 +9460,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; + /* 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); } - 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; - } - 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, @@ -9466,8 +9524,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, @@ -9719,6 +9781,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 */ @@ -9770,14 +9833,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); } } @@ -10567,11 +10636,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) @@ -10579,40 +10649,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 @@ -10719,32 +10776,40 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) /* 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 now we - * are assuming all CPUs using the same EQ will all share - * the same hardware queue. + * 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 cpu map entries to a IRQ - * on the same phys_id + * 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; @@ -10757,7 +10822,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) /* 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 + /* 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. @@ -10779,7 +10844,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) found_same: /* We found a matching phys_id, so copy the IRQ info */ cpup->eq = new_cpup->eq; - cpup->hdwq = new_cpup->hdwq; cpup->irq = new_cpup->irq; /* Bump start_cpu to the next slot to minmize the @@ -10790,12 +10854,11 @@ found_same: if (start_cpu == nr_cpumask_bits) start_cpu = first_cpu; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3337 Set Affinity: CPU %d " - "hdwq %d irq %d from id %d same " + "irq %d from id %d same " "phys_id (%d)\n", - cpu, cpup->hdwq, cpup->irq, - new_cpu, cpup->phys_id); + cpu, cpup->irq, new_cpu, cpup->phys_id); } } @@ -10810,7 +10873,7 @@ found_same: /* 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 + /* 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. @@ -10829,13 +10892,12 @@ found_same: /* We should never leave an entry unassigned */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3339 Set Affinity: CPU %d " - "hdwq %d irq %d UNASSIGNED\n", - cpu, cpup->hdwq, cpup->irq); + "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->hdwq = new_cpup->hdwq; cpup->irq = new_cpup->irq; /* Bump start_cpu to the next slot to minmize the @@ -10846,13 +10908,82 @@ found_any: if (start_cpu == nr_cpumask_bits) start_cpu = first_cpu; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3338 Set Affinity: CPU %d " - "hdwq %d irq %d from id %d (%d/%d)\n", - cpu, cpup->hdwq, cpup->irq, new_cpu, + "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; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4432060f7315..d55259fc0af5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5548,6 +5548,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); @@ -5555,18 +5556,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) { @@ -7858,20 +7865,22 @@ 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; @@ -14217,7 +14226,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; @@ -14502,7 +14511,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; @@ -14511,7 +14520,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, if (++cnt >= numq) break; } - return; } @@ -14539,7 +14547,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; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 69c6dba77dce..3aeca387b22a 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -452,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*/ @@ -552,6 +553,7 @@ struct lpfc_vector_map_info { 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 From 996a02aeb959414378ea6c620934450944f8c5db Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:07 -0700 Subject: [PATCH 073/185] scsi: lpfc: Fix fcp_rsp_len checking on lun reset Issuing a LUN reset was resulting in a command failure which then escalated to a host reset. The FCP-4 spec allows fcp_rsp_len field to specify the number of valid bytes of FCP_RSP_INFO, and the value could be 4 or 8. The driver is allowing only a value of 8, thus it failed the command. Revise the driver to allow 4 or 8. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 5a5a9bbe6023..f9df800e7067 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -4798,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, From 93f647f93df14742923133582ad603bf35628e92 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:08 -0700 Subject: [PATCH 074/185] scsi: lpfc: Fix FDMI fc4type for nvme support FDMI protocol support registration was not accurately showing nvme support. The fcponly-path clears the parameter object. Move the code out of the fcponly code path. Fix the FDMI registration data to properly check for nvme support. Commonize the manner in which the fdmi routines set protocol support. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 4812bbbf43cc..ec72c39997d2 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -2358,6 +2358,7 @@ 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; @@ -2366,9 +2367,13 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ - if (vport->nvmei_support || vport->phba->nvmet_support) - ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */ 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); @@ -2680,9 +2685,12 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, 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 */ - ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + size = FOURBYTES + 32; ad->AttrLen = cpu_to_be16(size); ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES); From aa6ff309187256ee542a8cf47adbfcfdaa888c46 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:09 -0700 Subject: [PATCH 075/185] scsi: lpfc: Fix BFS crash with DIX enabled Crashes in scsi_queue_rq or in dma_unmap_direct_sg during BFS when lpfc has lpfc_enable_bg=1. lpfc is setting DIX and prot sg after scsi_add_host_with_dma() has been called. The scsi_host_set_prot() and scsi_host_set_guard() routines need to be called before scsi_add_host_with_dma(). Revise the calling sequence to set the protection/guard data before calling scsi_add_host_with_dma(). Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 416f0fb155f5..a2b827dd36ff 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -94,6 +94,7 @@ 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_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; @@ -4348,6 +4349,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; @@ -7669,8 +7673,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); From 01d53c04637f96bbb753e9c7f61392c40671b564 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:10 -0700 Subject: [PATCH 076/185] scsi: lpfc: Fix kernel warnings related to smp_processor_id() Kernel warnings may be seen with preempt debugging enabled. Replace smp_processor_id calls with raw_smp_processor_id or cpu information stored in hdwq structures. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 36e8d842d973..eb93189f4544 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1642,7 +1642,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, 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); req = &ctxp->ctx.fcp_req; if (req) From 852eb63a7179249f95ba2e1faaabf403e39d88b3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 May 2019 17:49:11 -0700 Subject: [PATCH 077/185] scsi: lpfc: Update lpfc version to 12.2.0.3 Update lpfc version to 12.2.0.3 Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index f7d9ef428417..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.1" +#define LPFC_DRIVER_VERSION "12.2.0.3" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ From 2e22520475037f97b5a3234591183105ecf9845b Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Thu, 2 May 2019 19:50:56 -0500 Subject: [PATCH 078/185] scsi: ibmvscsi: Wire up host_reset() in the driver's scsi_host_template Wire up the host_reset function in our driver_template to allow a user requested adpater reset via the host_reset sysfs attribute. Example: echo "adapter" > /sys/class/scsi_host/host0/host_reset Signed-off-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 8cec5230fe31..65fc8ca962c5 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -2050,6 +2050,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 +2086,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, From 6e40de8b6b3cfa7288bb4a1fee2c7173f53b7345 Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Thu, 2 May 2019 19:50:57 -0500 Subject: [PATCH 079/185] scsi: ibmvscsi: redo driver work thread to use enum action states The current implemenation relies on two flags in the driver's private host structure to signal the need for a host reset or to reenable the CRQ after a LPAR migration. This patch does away with those flags and introduces a single action flag and defined enums for the supported kthread work actions. Lastly, the if/else logic is replaced with a switch statement. Signed-off-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 61 ++++++++++++++++++++++---------- drivers/scsi/ibmvscsi/ibmvscsi.h | 9 +++-- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 65fc8ca962c5..8df82c58e7b9 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -828,7 +828,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); } @@ -1797,7 +1797,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 { @@ -2116,48 +2116,71 @@ 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_NONE: + 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 - return; + break; + default: + break; + } + + 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: + 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..04bcbc832dc9 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -88,13 +88,18 @@ 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, +}; + /* 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; From aa343c695aa59f03f31a2f989b8c977a727e46e3 Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Thu, 2 May 2019 19:50:58 -0500 Subject: [PATCH 080/185] scsi: ibmvscsi: fix tripping of blk_mq_run_hw_queue WARN_ON After a successful SRP login response we call scsi_unblock_requests() to kick any pending IOs. The callback to process this SRP response happens in a tasklet and therefore is in softirq context. The result of such is that when blk-mq is enabled, it is no longer safe to call scsi_unblock_requests() from this context. The result of duing so triggers the following WARN_ON splat in dmesg after a host reset or CRQ reenablement. WARNING: CPU: 0 PID: 0 at block/blk-mq.c:1375 __blk_mq_run_hw_queue+0x120/0x180 Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.0.0-rc8 #4 NIP [c0000000009771e0] __blk_mq_run_hw_queue+0x120/0x180 LR [c000000000977484] __blk_mq_delay_run_hw_queue+0x244/0x250 Call Trace: __blk_mq_delay_run_hw_queue+0x244/0x250 blk_mq_run_hw_queue+0x8c/0x1c0 blk_mq_run_hw_queues+0x60/0x90 scsi_run_queue+0x1e4/0x3b0 scsi_run_host_queues+0x48/0x80 login_rsp+0xb0/0x100 ibmvscsi_handle_crq+0x30c/0x3e0 ibmvscsi_task+0x54/0xe0 tasklet_action_common.isra.3+0xc4/0x1a0 __do_softirq+0x174/0x3f4 irq_exit+0xf0/0x120 __do_irq+0xb0/0x210 call_do_irq+0x14/0x24 do_IRQ+0x9c/0x130 hardware_interrupt_common+0x14c/0x150 This patch fixes the issue by introducing a new host action for unblocking the scsi requests in our seperate work thread. Signed-off-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 5 ++++- drivers/scsi/ibmvscsi/ibmvscsi.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 8df82c58e7b9..727c31dc11a0 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1179,7 +1179,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); } /** @@ -2123,6 +2124,7 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) spin_lock_irqsave(hostdata->host->host_lock, flags); switch (hostdata->action) { case IBMVSCSI_HOST_ACTION_NONE: + case IBMVSCSI_HOST_ACTION_UNBLOCK: break; case IBMVSCSI_HOST_ACTION_RESET: spin_unlock_irqrestore(hostdata->host->host_lock, flags); @@ -2164,6 +2166,7 @@ static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) return 0; case IBMVSCSI_HOST_ACTION_RESET: case IBMVSCSI_HOST_ACTION_REENABLE: + case IBMVSCSI_HOST_ACTION_UNBLOCK: default: break; } diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 04bcbc832dc9..d9bf502334ba 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -92,6 +92,7 @@ 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 */ From 1697c6a64c49df3ed1a7e81845dcf2edf6ea23db Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 18 May 2019 21:47:24 +0200 Subject: [PATCH 081/185] scsi: fdomain: Add register definitions Add register bit definitions from documentation to header file and use them instead of magic constants. No changes to generated binary. Signed-off-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- drivers/scsi/fdomain.c | 144 +++++++++++++++++++------------------ drivers/scsi/fdomain.h | 117 ++++++++++++++++++++++-------- drivers/scsi/fdomain_isa.c | 4 +- 3 files changed, 167 insertions(+), 98 deletions(-) diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 19af1ae608df..297ccc799436 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -99,7 +99,7 @@ * up the machine. */ #define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ -#define PARITY_MASK 0x08 /* Parity enabled, 0x00 = disabled */ +#define PARITY_MASK ACTL_PAREN /* Parity enabled, 0 = disabled */ enum chip_type { unknown = 0x00, @@ -117,18 +117,19 @@ struct fdomain { static inline void fdomain_make_bus_idle(struct fdomain *fd) { - outb(0, fd->base + SCSI_Cntl); - outb(0, fd->base + SCSI_Mode_Cntl); + outb(0, fd->base + REG_BCTL); + outb(0, fd->base + REG_MCTL); if (fd->chip == tmc18c50 || fd->chip == tmc18c30) /* Clear forced intr. */ - outb(0x21 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK, + fd->base + REG_ACTL); else - outb(0x01 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL); } static enum chip_type fdomain_identify(int port) { - u16 id = inb(port + LSB_ID_Code) | inb(port + MSB_ID_Code) << 8; + u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8; switch (id) { case 0x6127: @@ -140,10 +141,10 @@ static enum chip_type fdomain_identify(int port) } /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */ - outb(0x80, port + IO_Control); - if ((inb(port + Configuration2) & 0x80) == 0x80) { - outb(0x00, port + IO_Control); - if ((inb(port + Configuration2) & 0x80) == 0x00) + 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. */ @@ -155,8 +156,8 @@ static int fdomain_test_loopback(int base) int i; for (i = 0; i < 255; i++) { - outb(i, base + Write_Loopback); - if (inb(base + Read_Loopback) != i) + outb(i, base + REG_LOOPBACK); + if (inb(base + REG_LOOPBACK) != i) return 1; } @@ -165,12 +166,12 @@ static int fdomain_test_loopback(int base) static void fdomain_reset(int base) { - outb(1, base + SCSI_Cntl); + outb(1, base + REG_BCTL); mdelay(20); - outb(0, base + SCSI_Cntl); + outb(0, base + REG_BCTL); mdelay(1150); - outb(0, base + SCSI_Mode_Cntl); - outb(PARITY_MASK, base + TMC_Cntl); + outb(0, base + REG_MCTL); + outb(PARITY_MASK, base + REG_ACTL); } static int fdomain_select(struct Scsi_Host *sh, int target) @@ -179,20 +180,20 @@ static int fdomain_select(struct Scsi_Host *sh, int target) unsigned long timeout; struct fdomain *fd = shost_priv(sh); - outb(0x82, fd->base + SCSI_Cntl); /* Bus Enable + Select */ - outb(BIT(sh->this_id) | BIT(target), fd->base + SCSI_Data_NoACK); + 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 + TMC_Cntl); + outb(PARITY_MASK, fd->base + REG_ACTL); timeout = 350; /* 350 msec */ do { - status = inb(fd->base + SCSI_Status); /* Read adapter status */ - if (status & 1) { /* Busy asserted */ + status = inb(fd->base + REG_BSTAT); + if (status & BSTAT_BSY) { /* Enable SCSI Bus */ /* (on error, should make bus idle with 0) */ - outb(0x80, fd->base + SCSI_Cntl); + outb(BCTL_BUSEN, fd->base + REG_BCTL); return 0; } mdelay(1); @@ -203,7 +204,7 @@ static int fdomain_select(struct Scsi_Host *sh, int target) static void fdomain_finish_cmd(struct fdomain *fd, int result) { - outb(0x00, fd->base + Interrupt_Cntl); + outb(0, fd->base + REG_ICTL); fdomain_make_bus_idle(fd); fd->cur_cmd->result = result; fd->cur_cmd->scsi_done(fd->cur_cmd); @@ -216,15 +217,15 @@ static void fdomain_read_data(struct scsi_cmnd *cmd) unsigned char *virt, *ptr; size_t offset, len; - while ((len = inw(fd->base + FIFO_Data_Count)) > 0) { + 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 + Read_FIFO); + *ptr++ = inb(fd->base + REG_FIFO); if (len > 1) - insw(fd->base + Read_FIFO, ptr, len >> 1); + insw(fd->base + REG_FIFO, ptr, len >> 1); scsi_set_resid(cmd, scsi_get_resid(cmd) - len); scsi_kunmap_atomic_sg(virt); } @@ -238,7 +239,7 @@ static void fdomain_write_data(struct scsi_cmnd *cmd) unsigned char *virt, *ptr; size_t offset, len; - while ((len = FIFO_Size - inw(fd->base + FIFO_Data_Count)) > 512) { + 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; @@ -249,9 +250,9 @@ static void fdomain_write_data(struct scsi_cmnd *cmd) &offset, &len); ptr = virt + offset; if (len & 1) - outb(*ptr++, fd->base + Write_FIFO); + outb(*ptr++, fd->base + REG_FIFO); if (len > 1) - outsw(fd->base + Write_FIFO, ptr, len >> 1); + outsw(fd->base + REG_FIFO, ptr, len >> 1); scsi_set_resid(cmd, scsi_get_resid(cmd) - len); scsi_kunmap_atomic_sg(virt); } @@ -270,66 +271,68 @@ static void fdomain_work(struct work_struct *work) spin_lock_irqsave(sh->host_lock, flags); if (cmd->SCp.phase & in_arbitration) { - status = inb(fd->base + TMC_Status); - if (!(status & 0x02)) { + 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(0x40 | FIFO_COUNT, fd->base + Interrupt_Cntl); - outb(0x82, fd->base + SCSI_Cntl); /* Bus Enable + Select */ - outb(BIT(cmd->device->host->this_id) | - BIT(scmd_id(cmd)), fd->base + SCSI_Data_NoACK); + 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(0x10 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); goto out; } else if (cmd->SCp.phase & in_selection) { - status = inb(fd->base + SCSI_Status); - if (!(status & 0x01)) { + 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(0x10 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); } cmd->SCp.phase = in_other; - outb(0x90 | FIFO_COUNT, fd->base + Interrupt_Cntl); - outb(0x80, fd->base + SCSI_Cntl); + 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 + SCSI_Status); + status = inb(fd->base + REG_BSTAT); - if (status & 0x10) { /* REQ */ + if (status & BSTAT_REQ) { switch (status & 0x0e) { - case 0x08: /* COMMAND OUT */ + case BSTAT_CMD: /* COMMAND OUT */ outb(cmd->cmnd[cmd->SCp.sent_command++], - fd->base + Write_SCSI_Data); + fd->base + REG_SCSI_DATA); break; - case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ + case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */ if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { cmd->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN | + PARITY_MASK, fd->base + REG_ACTL); } break; - case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ + case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */ if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { cmd->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK, + fd->base + REG_ACTL); } break; - case 0x0c: /* STATUS IN */ - cmd->SCp.Status = inb(fd->base + Read_SCSI_Data); + case BSTAT_CMD | BSTAT_IO: /* STATUS IN */ + cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA); break; - case 0x0a: /* MESSAGE OUT */ - outb(MESSAGE_REJECT, fd->base + Write_SCSI_Data); + case BSTAT_MSG | BSTAT_CMD: /* MESSAGE OUT */ + outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA); break; - case 0x0e: /* MESSAGE IN */ - cmd->SCp.Message = inb(fd->base + Read_SCSI_Data); + case BSTAT_MSG | BSTAT_IO | BSTAT_CMD: /* MESSAGE IN */ + cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA); if (!cmd->SCp.Message) ++done; break; @@ -340,10 +343,12 @@ static void fdomain_work(struct work_struct *work) cmd->SCp.sent_command >= cmd->cmd_len) { if (cmd->sc_data_direction == DMA_TO_DEVICE) { cmd->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN | + PARITY_MASK, fd->base + REG_ACTL); } else { cmd->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, fd->base + TMC_Cntl); + outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK, + fd->base + REG_ACTL); } } @@ -359,10 +364,12 @@ static void fdomain_work(struct work_struct *work) (DID_OK << 16)); } else { if (cmd->SCp.phase & disconnect) { - outb(0xd0 | FIFO_COUNT, fd->base + Interrupt_Cntl); - outb(0x00, fd->base + SCSI_Cntl); + outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT, + fd->base + REG_ICTL); + outb(0, fd->base + REG_BCTL); } else - outb(0x90 | FIFO_COUNT, fd->base + Interrupt_Cntl); + outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, + fd->base + REG_ICTL); } out: spin_unlock_irqrestore(sh->host_lock, flags); @@ -373,10 +380,10 @@ static irqreturn_t fdomain_irq(int irq, void *dev_id) struct fdomain *fd = dev_id; /* Is it our IRQ? */ - if ((inb(fd->base + TMC_Status) & 0x01) == 0) + if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0) return IRQ_NONE; - outb(0x00, fd->base + Interrupt_Cntl); + outb(0, fd->base + REG_ICTL); /* We usually have one spurious interrupt after each command. */ if (!fd->cur_cmd) /* Spurious interrupt */ @@ -406,12 +413,13 @@ static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd) fdomain_make_bus_idle(fd); /* Start arbitration */ - outb(0x00, fd->base + Interrupt_Cntl); - outb(0x00, fd->base + SCSI_Cntl); /* Disable data drivers */ - outb(BIT(cmd->device->host->this_id), - fd->base + SCSI_Data_NoACK); /* Set our id bit */ - outb(0x20, fd->base + Interrupt_Cntl); - outb(0x14 | PARITY_MASK, fd->base + TMC_Cntl); /* 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); diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h index fabb2e49461f..6f63fc6b0d12 100644 --- a/drivers/scsi/fdomain.h +++ b/drivers/scsi/fdomain.h @@ -12,34 +12,95 @@ enum { sent_ident = 0x40, }; -enum in_port_type { - Read_SCSI_Data = 0, - SCSI_Status = 1, - TMC_Status = 2, - FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ - Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ - LSB_ID_Code = 5, - MSB_ID_Code = 6, - Read_Loopback = 7, - SCSI_Data_NoACK = 8, - Interrupt_Status = 9, - Configuration1 = 10, - Configuration2 = 11, /* tmc18c50/tmc18c30 only */ - Read_FIFO = 12, - FIFO_Data_Count = 14 -}; - -enum out_port_type { - Write_SCSI_Data = 0, - SCSI_Cntl = 1, - Interrupt_Cntl = 2, - SCSI_Mode_Cntl = 3, - TMC_Cntl = 4, - Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ - Write_Loopback = 7, - IO_Control = 11, /* tmc18c30 only */ - Write_FIFO = 12 -}; +/* (@) = 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; diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c index bca5d56f12aa..28639adf8219 100644 --- a/drivers/scsi/fdomain_isa.c +++ b/drivers/scsi/fdomain_isa.c @@ -131,7 +131,7 @@ static int fdomain_isa_match(struct device *dev, unsigned int ndev) if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa")) return 0; - irq = irqs[(inb(base + Configuration1) & 0x0e) >> 1]; + irq = irqs[(inb(base + REG_CFG1) & 0x0e) >> 1]; if (sig) @@ -164,7 +164,7 @@ static int fdomain_isa_param_match(struct device *dev, unsigned int ndev) } if (irq_ <= 0) - irq_ = irqs[(inb(io[ndev] + Configuration1) & 0x0e) >> 1]; + irq_ = irqs[(inb(io[ndev] + REG_CFG1) & 0x0e) >> 1]; sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev); if (!sh) { From 8674a8aa2c399cb4014052796ba4bd0fbd6f3c03 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 27 May 2019 22:19:47 +0200 Subject: [PATCH 082/185] scsi: fdomain: Add PCMCIA support Add PCMCIA card support to Future Domain SCSI driver. Tested with IBM SCSI PCMCIA Adapter 40G1890. Signed-off-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- drivers/scsi/fdomain.c | 7 ++- drivers/scsi/pcmcia/Kconfig | 10 ++++ drivers/scsi/pcmcia/Makefile | 1 + drivers/scsi/pcmcia/fdomain_cs.c | 95 ++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 drivers/scsi/pcmcia/fdomain_cs.c diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 297ccc799436..b5e66971b6d9 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -510,6 +510,7 @@ struct Scsi_Host *fdomain_create(int base, int irq, int this_id, static const char * const chip_names[] = { "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30" }; + unsigned long irq_flags = 0; chip = fdomain_identify(base); if (!chip) @@ -541,8 +542,10 @@ struct Scsi_Host *fdomain_create(int base, int irq, int this_id, fd->chip = chip; INIT_WORK(&fd->work, fdomain_work); - if (request_irq(irq, fdomain_irq, dev_is_pci(dev) ? IRQF_SHARED : 0, - "fdomain", fd)) + 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", diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index 2d435f105b16..169d93f90a30 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -19,6 +19,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 + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#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); From 32877947b7a806bb655a830d9cab709a3aebd49b Mon Sep 17 00:00:00 2001 From: Weitao Hou Date: Mon, 20 May 2019 11:24:03 +0800 Subject: [PATCH 083/185] scsi: pm8001: Fix typo in code comments Fix abord to abort. Signed-off-by: Weitao Hou Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 88eef3b18e41..3de57c5a3299 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -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; From 8a914f32e2dfaff7f23002502ba64a2abb2a4a50 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Tue, 28 May 2019 06:51:52 +0530 Subject: [PATCH 084/185] scsi: target/iscsi: fix possible condition with no effect (if == else) Fix the following warning reported by coccicheck: drivers/target/iscsi/iscsi_target_nego.c:175:6-8: WARNING: possible condition with no effect (if == else) Signed-off-by: Hariprasad Kelam Reviewed-by: David Disseldorp Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_nego.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 8a5e8d17a942..92ce2fd05fdd 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -160,22 +160,11 @@ static u32 iscsi_handle_authentication( if (strstr("None", authtype)) return 1; -#ifdef CANSRP - else if (strstr("SRP", authtype)) - return srp_main_loop(conn, auth, in_buf, out_buf, - &in_length, out_length); -#endif else if (strstr("CHAP", authtype)) return chap_main_loop(conn, auth, in_buf, out_buf, &in_length, out_length); - else if (strstr("SPKM1", authtype)) - return 2; - else if (strstr("SPKM2", authtype)) - return 2; - else if (strstr("KRB5", authtype)) - return 2; - else - return 2; + /* SRP, SPKM1, SPKM2 and KRB5 are unsupported */ + return 2; } static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn) From 36631157eb3ff8b0b359d574452ebb8f81370ec5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 22 May 2019 09:39:03 +0100 Subject: [PATCH 085/185] scsi: hpsa: fix an uninitialized read and dereference of pointer dev Currently the check for a lockup_detected failure exits via the label return_reset_status that reads and dereferences an uninitialized pointer dev. Fix this by ensuring dev is inintialized to null. Addresses-Coverity: ("Uninitialized pointer read") Fixes: 14991a5bade5 ("scsi: hpsa: correct device resets") Signed-off-by: Colin Ian King Acked-by: Don Brace Reviewed-by: Nathan Chancellor Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c560a4532733..ac8338b0571b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5947,7 +5947,7 @@ 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; From a5c990eea5ddd587bcd9af6dc973a1653c8d94af Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Wed, 29 May 2019 22:21:36 +0200 Subject: [PATCH 086/185] scsi: lpfc: Use *_pool_zalloc rather than *_pool_alloc Use *_pool_zalloc rather than *_pool_alloc followed by memset with 0. Signed-off-by: Thomas Meyer Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a2b827dd36ff..1a8abb4b0974 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4116,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 From a1b6fb947f92352bc8edab901d773306c5b80b8b Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Mon, 20 May 2019 22:06:00 +0800 Subject: [PATCH 087/185] scsi: libsas: no need to join wide port again in sas_ex_discover_dev() Since we are processing events synchronously now, the second call of sas_ex_join_wide_port() in sas_ex_discover_dev() is not needed. There will be no races with other works in disco workqueue. So remove the second sas_ex_join_wide_port(). I did not change the return value of 'res' to error when discover failed because we need to continue to discover other phys if one phy discover failed. So let's keep that logic as before and just add a debug log to detect the failure. And directly return if second fanout expander attatched to the parent expander because it has nothing to do after the phy is disabled. Signed-off-by: Jason Yan Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 76ea83ddafa7..fd16a3debef4 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1090,7 +1090,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int 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); @@ -1102,27 +1102,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%02d 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; } From ee5f1042b20e1ffbc5c7eb0e0883fdbc05cec85f Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Tue, 21 May 2019 14:44:52 +0800 Subject: [PATCH 088/185] scsi: ufs: Introduce ufshcd_is_auto_hibern8_supported() The checking of Auto-Hibernation support is used in many places in the driver, thus re-factor it as ufshcd_is_auto_hibern8_supported() to make code more clean. Signed-off-by: Stanley Chu Reviewed-by: Bean Huo Reviewed-by: Alim Akhtar Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-sysfs.c | 6 +++--- drivers/scsi/ufs/ufshcd.c | 4 ++-- drivers/scsi/ufs/ufshcd.h | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) 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/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 8c1c551f2b42..0cf698d05426 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3907,7 +3907,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); @@ -8312,7 +8312,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 = 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) \ From f571b377ded7466e175e73c116df9ae09527dcb0 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Tue, 21 May 2019 14:44:53 +0800 Subject: [PATCH 089/185] scsi: ufs: Do not overwrite Auto-Hibernate timer Some vendor-specific initialization flow may set its own auto-hibernate timer. In this case, do not overwrite timer value as "default value" in ufshcd_init(). Signed-off-by: Stanley Chu Reviewed-by: Alim Akhtar Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0cf698d05426..7cd757558203 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8312,7 +8312,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 (ufshcd_is_auto_hibern8_supported(hba)) { + 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); } From 821744403913d957cb52263b2016fd5bd29c30d0 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Tue, 21 May 2019 14:44:54 +0800 Subject: [PATCH 090/185] scsi: ufs: Add error-handling of Auto-Hibernate Currently auto-hibernate is activated if host supports auto-hibern8 capability. However error-handling is not implemented, which makes the feature somewhat risky. If either "Hibernate Enter" or "Hibernate Exit" fail during auto-hibernate flow, the corresponding interrupt "UIC_HIBERNATE_ENTER" or "UIC_HIBERNATE_EXIT" shall be raised according to UFS specification. This patch adds auto-hibernate error-handling: - Monitor "Hibernate Enter" and "Hibernate Exit" interrupts after auto-hibernate feature is activated. - If a failure happens, trigger error-handling just like "manual-hibernate" failure and apply the same recovery flow: schedule UFS error handler in ufshcd_check_errors(), and then do host reset and restore in UFS error handler. Signed-off-by: Stanley Chu Reviewed-by: Bean Huo Reviewed-by: Alim Akhtar Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 31 +++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshci.h | 6 ++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7cd757558203..a208589426b1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5254,6 +5254,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 +5414,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 +5449,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 +5520,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); 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) From f9e3ebeea4521652318af903cddeaf033527e93e Mon Sep 17 00:00:00 2001 From: Gen Zhang Date: Thu, 30 May 2019 09:10:30 +0800 Subject: [PATCH 091/185] scsi: mpt3sas_ctl: fix double-fetch bug in _ctl_ioctl_main() In _ctl_ioctl_main(), 'ioctl_header' is fetched the first time from userspace. 'ioctl_header.ioc_number' is then checked. The legal result is saved to 'ioc'. Then, in condition MPT3COMMAND, the whole struct is fetched again from the userspace. Then _ctl_do_mpt_command() is called, 'ioc' and 'karg' as inputs. However, a malicious user can change the 'ioc_number' between the two fetches, which will cause a potential security issues. Moreover, a malicious user can provide a valid 'ioc_number' to pass the check in first fetch, and then modify it in the second fetch. To fix this, we need to recheck the 'ioc_number' in the second fetch. Signed-off-by: Gen Zhang Acked-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index b2bb47c14d35..5181c03e82a6 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -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); From dea98ba45a187fd6fa836b070e95a8ba68499bb4 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 25 May 2019 20:38:21 +0800 Subject: [PATCH 092/185] scsi: megaraid_sas: remove set but not used variable 'cur_state' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/megaraid/megaraid_sas_base.c: In function megasas_transition_to_ready: drivers/scsi/megaraid/megaraid_sas_base.c:3900:6: warning: variable cur_state set but not used [-Wunused-but-set-variable] Never used since commit 7218df69e360 ("[SCSI] megaraid_sas: use the firmware boot timeout when waiting for commands") Signed-off-by: YueHaibing Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 3a9128ed304d..5397b12d5117 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3909,7 +3909,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); @@ -3930,7 +3929,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) abs_state & MFI_STATE_FAULT_SUBCODE, __func__); if (ocr) { max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FAULT; break; } else { dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); @@ -3956,7 +3954,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: @@ -3972,7 +3969,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: @@ -4005,7 +4001,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: @@ -4013,32 +4008,26 @@ 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: From de19212c2890d1bb1e2d0e303affba620b86819b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 25 May 2019 20:42:02 +0800 Subject: [PATCH 093/185] scsi: megaraid_sas: remove set but not used variables 'host' and 'wait_time' Fixes gcc '-Wunused-but-set-variable' warnings: drivers/scsi/megaraid/megaraid_sas_base.c: In function megasas_suspend: drivers/scsi/megaraid/megaraid_sas_base.c:7269:20: warning: variable host set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_sas_base.c: In function megasas_aen_polling: drivers/scsi/megaraid/megaraid_sas_base.c:8397:15: warning: variable wait_time set but not used [-Wunused-but-set-variable] 'host' never used since introduction in commit 31ea7088974c ("[SCSI] megaraid_sas: add hibernation support") 'wait_time' never used since commit 11c71cb4ab7c ("megaraid_sas: Do not allow PCI access during OCR") Signed-off-by: YueHaibing Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5397b12d5117..b64b436c6be4 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -7267,11 +7267,9 @@ 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; instance->unload = 1; dev_info(&pdev->dev, "%s is called\n", __func__); @@ -8395,7 +8393,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; @@ -8405,10 +8403,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); From b3b2a9f60fd9e38c45d4728cac78ddf5596f3bb0 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 22 May 2019 21:31:49 +0530 Subject: [PATCH 094/185] scsi: message: fusion: Use kmemdup instead of memcpy and kmalloc Replace kmalloc + memcpy with kmemdup. This was reported by coccinelle. Signed-off-by: Bharath Vedartham Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptbase.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index d8882b0a1338..c2dd322691d1 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6001,13 +6001,12 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) if (mpt_config(ioc, &cfg) != 0) goto out; - mem = kmalloc(iocpage2sz, GFP_KERNEL); + mem = kmemdup(pIoc2, iocpage2sz, GFP_KERNEL); if (!mem) { rc = -ENOMEM; goto out; } - memcpy(mem, (u8 *)pIoc2, iocpage2sz); ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; mpt_read_ioc_pg_3(ioc); From 6c86e046cf97b4a03d6166ba95b3f448455abbb0 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Wed, 29 May 2019 17:58:42 +0800 Subject: [PATCH 095/185] scsi: hisi_sas: Delete PHY timers when rmmod or probe failed When removing the driver or when probe fails, we need to delete the PHY timers. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8a7feb8ed8d6..256f93e6f89f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2480,6 +2480,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); } From 794327ab53cc6b330774d6fdb93b547666583db9 Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Wed, 29 May 2019 17:58:43 +0800 Subject: [PATCH 096/185] scsi: hisi_sas: Fix the issue of argument mismatch of printing ecc errors The argument of dev_err() called by multi_bit_ecc_error_process_v3_hw() is not right. We pass two arguments, but there is only one printk format specifier in the string. Also move the print format string to dev_err(). Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 46 ++++++++++++++------------ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 25 +++++++------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index d4650bed8274..b8c0ba778293 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -427,70 +427,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 +500,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, }, }; @@ -2978,7 +2978,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); } } } @@ -2997,7 +2998,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); } } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 49620c2411df..3efb1e72bdab 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1831,77 +1831,77 @@ 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 found: ram addr 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_eccbad_intr found: ram addr 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_eccbad_intr found: ram addr 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_eccbad_intr found: mem addr 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_eccbad_intr found: mem addr 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_eccbad_intr 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_eccbad_intr found: mem addr 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_eccbad_intr found: mem addr 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_eccbad_intr found: mem addr 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_eccbad_intr found: mem addr is 0x%08X\n", + .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 found: ROB_ECC_ERR_ADDR=0x%08X\n", + .msg = "ooo_ram_eccbad_intr", .reg = AM_ROB_ECC_ERR_ADDR, }, }; @@ -1920,7 +1920,8 @@ static void multi_bit_ecc_error_process_v3_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); } } From c7669f50121ac43d33fe8fe7c38f737c6c35e323 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 29 May 2019 17:58:44 +0800 Subject: [PATCH 097/185] scsi: hisi_sas: Reduce HISI_SAS_SGE_PAGE_CNT in size Macro HISI_SAS_SGE_PAGE_CNT is defined to SG_CHUNK_SIZE, which is 128. This means that sizeof(struct hisi_sas_slot_buf_table) is 4192. This is just over a 4K, which can mean inefficient DMA memory usage (for no PI). Reduce the size of HISI_SAS_SGE_PAGE_CNT to 124 to fit in a 4K page. With this change, we experience no performance hit. Cc: dann frazier Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index fc87994b5d73..06f22fb372b1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -484,12 +484,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); From 0ab7bc825a12100bff27f82b8bc1eb7aaf929248 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Wed, 29 May 2019 17:58:45 +0800 Subject: [PATCH 098/185] scsi: hisi_sas: Change the type of some numbers to unsigned It reports a error as follows from some tools at two places in our code: runtime error: left shift of 4 by 29 places cannot be represented in type 'int' So change the type of the two numbers to unsigned to avoid the error. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 3efb1e72bdab..492ada65d41a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1344,7 +1344,7 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, 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: @@ -1412,7 +1412,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) | From e4c19deba6078c41fab2cb2ea0088088db228c21 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Wed, 29 May 2019 17:58:46 +0800 Subject: [PATCH 099/185] scsi: hisi_sas: Ignore the error code between phy down to phy up Several error codes will be generated between PHY down to up. This issue was introduced by HW design. The designers came to the conclusion that we should ignore these errors. Signed-off-by: Jiaxing Luo Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 492ada65d41a..fbf0a1e9c8c2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -911,8 +911,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); @@ -923,6 +929,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) From 97fcf176b43bedcfd64cca5fd7e07e2cd2bde284 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Wed, 29 May 2019 17:58:47 +0800 Subject: [PATCH 100/185] scsi: hisi_sas: Disable stash for v3 hw For v3 hw, stash is enabled to promote performance, but it does little to improve performance according to current tests. What's more, it causes exceptions for some situations, so disable it. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index fbf0a1e9c8c2..b92aa6b37e1d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -28,6 +28,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 @@ -554,6 +555,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) /* 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); From a90ef98b21cf40784af7ace77038f8341a7b96c8 Mon Sep 17 00:00:00 2001 From: Enzo Matsumiya Date: Tue, 7 May 2019 12:39:05 -0300 Subject: [PATCH 101/185] scsi: qla2xxx: remove double assignment in qla2x00_update_fcport Remove double assignment in qla2x00_update_fcport(). Signed-off-by: Enzo Matsumiya Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 54772d4c377f..4059655639d9 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5403,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) { From a82b3539dc27b3a85f0c46c9bc398734fdd08260 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 31 May 2019 23:27:45 +0800 Subject: [PATCH 102/185] scsi: lpfc: Remove set but not used variables 'qp' Fixes gcc '-Wunused-but-set-variable' warnings: drivers/scsi/lpfc/lpfc_init.c: In function lpfc_setup_cq_lookup: drivers/scsi/lpfc/lpfc_init.c:9359:30: warning: variable qp set but not used [-Wunused-but-set-variable] It's not used since commit e70596a60f88 ("scsi: lpfc: Fix poor use of hardware queues if fewer irq vectors") Signed-off-by: YueHaibing Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1a8abb4b0974..3096a444ef01 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -9356,10 +9356,8 @@ 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 */ From d7b761b0694986ea811c0daaa1178bfaaddf036d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 31 May 2019 23:28:41 +0800 Subject: [PATCH 103/185] scsi: lpfc: Make some symbols static Fix sparse warnings: drivers/scsi/lpfc/lpfc_sli.c:115:1: warning: symbol 'lpfc_sli4_pcimem_bcopy' was not declared. Should it be static? drivers/scsi/lpfc/lpfc_sli.c:7854:1: warning: symbol 'lpfc_sli4_process_missed_mbox_completions' was not declared. Should it be static? drivers/scsi/lpfc/lpfc_nvmet.c:223:27: warning: symbol 'lpfc_nvmet_get_ctx_for_xri' was not declared. Should it be static? drivers/scsi/lpfc/lpfc_nvmet.c:245:27: warning: symbol 'lpfc_nvmet_get_ctx_for_oxid' was not declared. Should it be static? drivers/scsi/lpfc/lpfc_init.c:75:10: warning: symbol 'lpfc_present_cpu' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: YueHaibing Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 +- drivers/scsi/lpfc/lpfc_nvmet.c | 4 ++-- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 3096a444ef01..6d6b14295734 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 *); diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index eb93189f4544..e471bbcca838 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -220,7 +220,7 @@ lpfc_nvmet_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } -struct lpfc_nvmet_rcv_ctx * +static struct lpfc_nvmet_rcv_ctx * lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) { struct lpfc_nvmet_rcv_ctx *ctxp; @@ -242,7 +242,7 @@ lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) return NULL; } -struct lpfc_nvmet_rcv_ctx * +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; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d55259fc0af5..337e4f105f23 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -108,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; @@ -7859,7 +7859,7 @@ 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; From 961ed94e8a83d8881546a278bf844699af92a502 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 3 Jun 2019 16:44:06 -0700 Subject: [PATCH 104/185] scsi: ibmvscsi: Don't use rc uninitialized in ibmvscsi_do_work clang warns: drivers/scsi/ibmvscsi/ibmvscsi.c:2126:7: warning: variable 'rc' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized] case IBMVSCSI_HOST_ACTION_NONE: ^~~~~~~~~~~~~~~~~~~~~~~~~ drivers/scsi/ibmvscsi/ibmvscsi.c:2151:6: note: uninitialized use occurs here if (rc) { ^~ Initialize rc in the IBMVSCSI_HOST_ACTION_UNBLOCK case statement then shuffle IBMVSCSI_HOST_ACTION_NONE down to the default case statement and make it return early so that rc is never used uninitialized in this function. Fixes: 035a3c4046b5 ("scsi: ibmvscsi: redo driver work thread to use enum action states") Link: https://github.com/ClangBuiltLinux/linux/issues/502 Suggested-by: Michael Ellerman Suggested-by: Tyrel Datwyler Signed-off-by: Nathan Chancellor Acked-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 727c31dc11a0..fcfaf037b5bf 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -2123,8 +2123,8 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) spin_lock_irqsave(hostdata->host->host_lock, flags); switch (hostdata->action) { - case IBMVSCSI_HOST_ACTION_NONE: case IBMVSCSI_HOST_ACTION_UNBLOCK: + rc = 0; break; case IBMVSCSI_HOST_ACTION_RESET: spin_unlock_irqrestore(hostdata->host->host_lock, flags); @@ -2142,8 +2142,10 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); break; + case IBMVSCSI_HOST_ACTION_NONE: default: - break; + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return; } hostdata->action = IBMVSCSI_HOST_ACTION_NONE; From 0824721463bc0c9394838af771dc7a8995065efa Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Thu, 6 Jun 2019 17:33:05 +0200 Subject: [PATCH 105/185] scsi: MAINTAINERS: update maintainer for PM8001 Lindar's email addess is bouncing for some time, just remove it. ProfitBricks was rebranded to 1 & 1 Cloud IONOS, so update my email address too. Signed-off-by: Jack Wang Signed-off-by: Martin K. Petersen --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index adfb7ffb40ca..2ea74d387451 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12544,8 +12544,7 @@ S: Orphan F: drivers/scsi/pmcraid.* PMC SIERRA PM8001 DRIVER -M: Jack Wang -M: lindar_liu@usish.com +M: Jack Wang L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/pm8001/ From 336df6eb628298e27e40e23d1eb00a0fb7083269 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 5 Jun 2019 22:24:21 -0700 Subject: [PATCH 106/185] scsi: lpfc: Avoid unused function warnings When building powerpc pseries_defconfig or powernv_defconfig: drivers/scsi/lpfc/lpfc_nvmet.c:224:1: error: unused function 'lpfc_nvmet_get_ctx_for_xri' [-Werror,-Wunused-function] drivers/scsi/lpfc/lpfc_nvmet.c:246:1: error: unused function 'lpfc_nvmet_get_ctx_for_oxid' [-Werror,-Wunused-function] These functions are only compiled when CONFIG_NVME_TARGET_FC is enabled. Use that same condition so there is no more warning. While the fixes commit did not introduce these functions, it caused these warnings. Fixes: 4064b27417a7 ("scsi: lpfc: Make some symbols static") Signed-off-by: Nathan Chancellor Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index e471bbcca838..f3d9a5545164 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -220,6 +220,7 @@ lpfc_nvmet_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } +#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) { @@ -263,6 +264,7 @@ lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) return NULL; } +#endif static void lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) From ed17190941c795314a5dcc2e8d48107aed0f8782 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 25 May 2019 20:37:05 +0800 Subject: [PATCH 107/185] scsi: megaraid_sas: remove set but not used variable 'sge_sz' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/megaraid/megaraid_sas_base.c: In function megasas_create_frame_pool: drivers/scsi/megaraid/megaraid_sas_base.c:4124:6: warning: variable sge_sz set but not used [-Wunused-but-set-variable] It's not used any more since commit 200aed582d61 ("megaraid_sas: endianness related bug fixes and code optimization") Signed-off-by: YueHaibing Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index b64b436c6be4..f8d851ff160e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4122,22 +4122,11 @@ 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 From cdf79db476c44c580045e9e0937288502e00eaad Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 25 May 2019 20:40:06 +0800 Subject: [PATCH 108/185] scsi: megaraid_sas: remove set but not used variables 'buff_addr' and 'ci_h' Fixes gcc '-Wunused-but-set-variable' warnings: drivers/scsi/megaraid/megaraid_sas_base.c: In function megasas_fw_crash_buffer_show: drivers/scsi/megaraid/megaraid_sas_base.c:3138:16: warning: variable buff_addr set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_sas_base.c: In function megasas_get_pd_list: drivers/scsi/megaraid/megaraid_sas_base.c:4426:13: warning: variable ci_h set but not used [-Wunused-but-set-variable] 'buff_addr' is never used since inroduction in commit fc62b3fc9021 ("megaraid_sas : Firmware crash dump feature support") 'ci_h' is not used since commit 9b3d028f3468 ("scsi: megaraid_sas: Pre-allocate frequently used DMA buffers") Signed-off-by: YueHaibing Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index f8d851ff160e..46effaa3c9f3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3147,7 +3147,6 @@ megasas_fw_crash_buffer_show(struct device *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; @@ -3164,8 +3163,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"); @@ -4413,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 " @@ -4422,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); From deff37063351ddf5defe1027b172548fdfbdcbe6 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Wed, 29 May 2019 18:00:39 +0200 Subject: [PATCH 109/185] scsi: megaraid_sas: make max_sectors visible in sys Support is easier with all driver parameters visible in sysfs. Signed-off-by: Tomas Henzl Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 46effaa3c9f3..ae9ac318fef3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -64,7 +64,7 @@ * 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, S_IRUGO); MODULE_PARM_DESC(max_sectors, "Maximum number of sectors per IO command"); From ea14e46240fee24f125610d3038183d68ae75b80 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Wed, 29 May 2019 18:00:40 +0200 Subject: [PATCH 110/185] scsi: megaraid_sas: use octal permissions instead of constants Checkpatch emits a warning when using symbolic permissions. Use octal permissions instead. No functional change. Signed-off-by: Tomas Henzl Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 20 ++++++++++---------- drivers/scsi/megaraid/megaraid_sas_fp.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ae9ac318fef3..a4fd70ef09c5 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -64,45 +64,45 @@ * 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, S_IRUGO); +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."); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 9ac357619b28..d296255a4f12 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -58,7 +58,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"); From d635468349695e6f2286400eb7a740f1635000b4 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Wed, 29 May 2019 18:00:41 +0200 Subject: [PATCH 111/185] scsi: megaraid_sas: use DEVICE_ATTR_{RO, RW} Use existing macros. No functional change. Signed-off-by: Tomas Henzl Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 44 ++++++++++------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index a4fd70ef09c5..54908981b382 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3121,7 +3121,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); @@ -3140,7 +3140,7 @@ 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); @@ -3182,7 +3182,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); @@ -3194,7 +3194,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); @@ -3229,7 +3229,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); @@ -3240,14 +3240,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); @@ -3257,7 +3257,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); @@ -3267,7 +3267,7 @@ megasas_fw_cmds_outstanding_show(struct device *cdev, } static ssize_t -megasas_dump_system_regs_show(struct device *cdev, +dump_system_regs_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3278,7 +3278,7 @@ megasas_dump_system_regs_show(struct device *cdev, } static ssize_t -megasas_raid_map_id_show(struct device *cdev, struct device_attribute *attr, +raid_map_id_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3289,22 +3289,14 @@ megasas_raid_map_id_show(struct device *cdev, struct device_attribute *attr, (unsigned long)instance->map_id); } -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 DEVICE_ATTR(dump_system_regs, S_IRUGO, - megasas_dump_system_regs_show, NULL); -static DEVICE_ATTR(raid_map_id, S_IRUGO, - megasas_raid_map_id_show, NULL); +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, From bc7625795cb993de0297b0e010d70dde75ad75ff Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 1 Jun 2019 03:18:06 +0000 Subject: [PATCH 112/185] scsi: megaraid_sas: Remove unused including Remove including that don't need it. Signed-off-by: YueHaibing Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_debugfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c index e52837bb6807..c69760775efa 100644 --- a/drivers/scsi/megaraid/megaraid_sas_debugfs.c +++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c @@ -25,7 +25,6 @@ * * Send feedback to: megaraidlinux.pdl@broadcom.com */ -#include #include #include #include From ec0a95aba4be8b217081883c79fcf2bbd9453916 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 7 Jun 2019 13:27:36 +0200 Subject: [PATCH 113/185] scsi: aic7xxx: Spelling s/configuraion/configuration/ Signed-off-by: Geert Uytterhoeven Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic7xxx.reg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From 881a9a54da175aa5897b8fef7abe0f85a5242770 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 7 Jun 2019 13:34:26 +0200 Subject: [PATCH 114/185] scsi: isci: Grammar s/the its/its/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/request.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 1b18cf55167e..c552b4b59717 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; @@ -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; From 078a4cc1380de7d4857e6db31c1d1ae9bdd56cc7 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:34 -0400 Subject: [PATCH 115/185] scsi: mpt3sas: function pointers of request descriptor This code refactoring introduces function pointers. Host uses Request Descriptors of different types for posting an entry onto a request queue. Based on controller type and capabilities, host can also use atomic descriptors other than normal descriptors. Using function pointer will avoid if-else statements Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 38 +++++++++++++----------- drivers/scsi/mpt3sas/mpt3sas_base.h | 3 ++ drivers/scsi/mpt3sas/mpt3sas_config.c | 2 +- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 20 ++++++------- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 20 ++++++------- drivers/scsi/mpt3sas/mpt3sas_transport.c | 8 ++--- 6 files changed, 49 insertions(+), 42 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 8aacbd1e7db2..ab0392a60d38 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1282,7 +1282,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: @@ -3485,7 +3485,8 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) * @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; @@ -3529,13 +3530,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; @@ -3552,13 +3553,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; @@ -3616,12 +3617,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; @@ -3952,7 +3953,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); @@ -5431,7 +5432,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 || @@ -5510,7 +5511,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)) { @@ -5914,7 +5915,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__); @@ -5973,7 +5974,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; } @@ -6089,7 +6090,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__); @@ -6587,6 +6588,9 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) break; } + 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 diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 480219f0efc5..d3f3c37f0060 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1422,6 +1422,9 @@ 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; }; diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index fb0a17252f86..b18cbbc0696c 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, diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 5181c03e82a6..b5cae58219b9 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); diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 1ccfbc7eebe0..1008c5e30274 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -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: @@ -7601,7 +7601,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 +9633,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)) { 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)) { From 79c74d03d527f8bd6727eba4ed4c22f6b0bca14d Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:35 -0400 Subject: [PATCH 116/185] scsi: mpt3sas: Add Atomic RequestDescriptor support on Aero If the Aero HBA supports Atomic Request Descriptors, it sets the Atomic Request Descriptor Capable bit in the IOCCapabilities field of the IOCFacts Reply message. Driver uses an Atomic Request Descriptor as an alternative method for posting an entry onto a request queue. The posting of an Atomic Request Descriptor is an atomic operation, providing a safe mechanism for multiple processors on the host to post requests without synchronization. This Atomic Request Descriptor format is identical to first 32 bits of Default Request Descriptor and uses only 32 bits. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 118 +++++++++++++++++++++++++--- drivers/scsi/mpt3sas/mpt3sas_base.h | 2 + 2 files changed, 111 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index ab0392a60d38..9cdbd61b4971 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3653,6 +3653,95 @@ _base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) &ioc->scsi_lookup_lock); } +/** + * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using + * Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * @handle: device handle, unused in this function, for function type match + * + * Return nothing. + */ +static void +_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 handle) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** + * _base_put_smid_fast_path_atomic - send fast path request to firmware + * using Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * @handle: device handle, unused in this function, for function type match + * Return nothing + */ +static void +_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 handle) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; + descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** + * _base_put_smid_hi_priority_atomic - send Task Management request to + * firmware using Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * @msix_task: msix_task will be same as msix of IO incase of task abort else 0 + * + * Return nothing. + */ +static void +_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 msix_task) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + descriptor.MSIxIndex = msix_task; + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** + * _base_put_smid_default - Default, primarily used for config pages + * use Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +static void +_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + /** * _base_display_OEMs_branding - Display branding string * @ioc: per adapter object @@ -5694,6 +5783,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); @@ -6587,15 +6679,23 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) break; } - - 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; - + 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. diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index d3f3c37f0060..3309864fe04a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1147,6 +1147,7 @@ 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. */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -1412,6 +1413,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; From 18fd3d8cf903404b2c7cd31a083be4db2e6a2a76 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:36 -0400 Subject: [PATCH 117/185] scsi: mpt3sas: Add flag high_iops_queues Aero controllers support balanced performance mode through the ability to configure queues with different properties. Reply queues with interrupt coalescing enabled are called "high iops reply queues" and reply queues with interrupt coalescing disabled are called "low latency reply queues". The driver configures a combination of high iops and low latency reply queues if: - HBA is an AERO controller; - MSI-X vectors supported by the HBA is 128; - Total CPU count in the system more than high iops queue count; - Driver is loaded with default max_msix_vectors module parameter; and - System booted in non-kdump mode. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 45 +++++++++++++++++++++++++---- drivers/scsi/mpt3sas/mpt3sas_base.h | 5 ++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 9cdbd61b4971..6d1a64866fd9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2912,6 +2912,34 @@ _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) +{ + + 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 @@ -2948,11 +2976,14 @@ _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->msix_vector_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); - 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); + _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); if (!ioc->rdpq_array_enable && max_msix_vectors == -1) local_max_msix_vectors = (reset_devices) ? 1 : 8; @@ -2991,11 +3022,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) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 3309864fe04a..bbbeb88c5a07 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -355,6 +355,10 @@ struct mpt3sas_nvme_cmd { #define VIRTUAL_IO_FAILED_RETRY (0x32010081) +/* High IOPs definitions */ +#define MPT3SAS_HIGH_IOPS_REPLY_QUEUES 8 +#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 */ @@ -1209,6 +1213,7 @@ struct MPT3SAS_ADAPTER { atomic64_t total_io_cnt; bool msix_load_balance; u16 thresh_hold; + u8 high_iops_queues; /* internal commands, callback index */ u8 scsi_io_cb_idx; From 0213651609b91180d1645388d35d6e77d7e0a886 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:37 -0400 Subject: [PATCH 118/185] scsi: mpt3sas: change _base_get_msix_index prototype Code refactoring. In function _base_get_msix_index, add scmd as second argument. This change is made in preparation for the next patch where we introduce a new function to get the MSI-X index for high iops queues. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 30 +++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 6d1a64866fd9..57d0e7de1631 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3300,8 +3300,18 @@ 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) @@ -3360,7 +3370,7 @@ 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->msix_io = _base_get_msix_index(ioc, NULL); request->smid = smid; INIT_LIST_HEAD(&request->chain_list); return smid; @@ -3534,7 +3544,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, _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_get_msix_index(ioc, NULL); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3556,7 +3566,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_get_msix_index(ioc, NULL); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3579,7 +3589,7 @@ _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_get_msix_index(ioc, NULL); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3643,7 +3653,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_get_msix_index(ioc, NULL); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -3675,7 +3685,7 @@ _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_get_msix_index(ioc, NULL); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -3705,7 +3715,7 @@ _base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, u32 *request = (u32 *)&descriptor; descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.MSIxIndex = _base_get_msix_index(ioc, NULL); descriptor.SMID = cpu_to_le16(smid); writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); @@ -3727,7 +3737,7 @@ _base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, u32 *request = (u32 *)&descriptor; descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; - descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.MSIxIndex = _base_get_msix_index(ioc, NULL); descriptor.SMID = cpu_to_le16(smid); writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); @@ -3771,7 +3781,7 @@ _base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) u32 *request = (u32 *)&descriptor; descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.MSIxIndex = _base_get_msix_index(ioc); + descriptor.MSIxIndex = _base_get_msix_index(ioc, NULL); descriptor.SMID = cpu_to_le16(smid); writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); From 5dd48a555a40431787e4e780ec6b3a7632250853 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:38 -0400 Subject: [PATCH 119/185] scsi: mpt3sas: Use high iops queues under some circumstances The driver will use round-robin method for io submission in batches within the high iops queues when the number of in-flight ios on the target device is larger than 8. Otherwise the driver will use low latency reply queues. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 36 ++++++++++++++++++++++++++++- drivers/scsi/mpt3sas/mpt3sas_base.h | 14 ++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 57d0e7de1631..74cb060e594f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3322,6 +3322,35 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc, 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 @@ -6707,6 +6736,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: @@ -6721,7 +6751,11 @@ 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->atomic_desc_capable) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index bbbeb88c5a07..85db1f261380 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -356,7 +356,9 @@ 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 */ @@ -928,6 +930,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 { @@ -1029,6 +1037,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @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 @@ -1152,6 +1162,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * 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; @@ -1211,6 +1222,7 @@ struct MPT3SAS_ADAPTER { 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; @@ -1432,7 +1444,7 @@ struct MPT3SAS_ADAPTER { 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, From 998c3001d31a278c9fb5cf68a2b0285dc7c76cdd Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:39 -0400 Subject: [PATCH 120/185] scsi: mpt3sas: save and use MSI-X index for posting RD In the IO submission path _base_get_msix_index is called twice. Initially while getting the smid and subsequently while posting the request descriptor (RD). Refactor code to query msix index only while posting the request descriptor. Save determined msix index in msix_io field. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 42 ++++++++++++++++++++++------ drivers/scsi/mpt3sas/mpt3sas_base.h | 1 + drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1 + 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 74cb060e594f..8779d2b04fad 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3399,8 +3399,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, NULL); request->smid = smid; + request->scmd = scmd; INIT_LIST_HEAD(&request->chain_list); return smid; } @@ -3454,6 +3454,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; } @@ -3552,6 +3553,29 @@ _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 @@ -3573,7 +3597,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, _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, NULL); + 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; @@ -3595,7 +3619,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, NULL); + 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; @@ -3618,7 +3642,7 @@ _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, NULL); + 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; @@ -3682,7 +3706,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, NULL); + 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; @@ -3714,7 +3738,7 @@ _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, NULL); + 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; @@ -3744,7 +3768,7 @@ _base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, u32 *request = (u32 *)&descriptor; descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.MSIxIndex = _base_get_msix_index(ioc, NULL); + descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SMID = cpu_to_le16(smid); writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); @@ -3766,7 +3790,7 @@ _base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, u32 *request = (u32 *)&descriptor; descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; - descriptor.MSIxIndex = _base_get_msix_index(ioc, NULL); + descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SMID = cpu_to_le16(smid); writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); @@ -3810,7 +3834,7 @@ _base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) u32 *request = (u32 *)&descriptor; descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.MSIxIndex = _base_get_msix_index(ioc, NULL); + descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SMID = cpu_to_le16(smid); writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 85db1f261380..f3818e30baed 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -830,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; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 1008c5e30274..3e93c4ab841b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -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); From 728bbc6cbff70051813730fb7977f5d99d867e12 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:40 -0400 Subject: [PATCH 121/185] scsi: mpt3sas: Affinity high iops queues IRQs to local node High iops queues are mapped to non-managed irqs. Set affinity of non-managed irqs to local numa node. Low latency queues are mapped to managed irqs. Driver reserves some reply queues for max iops (through pci_alloc_irq_vectors_affinity and .pre_vectors interface). The rest of queues are for low latency. Based on io workload in io submission path, driver will decide which group of reply queues (either high iops queues or low latency queues) to be used. High iops queues will be mapped to local numa node of controller and low latency queues will be mapped to cpus across numa nodes. In general, high iops and low latency queues should fit into 128 reply queues which is the max number of reply queues supported by Aero/Sea. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 73 ++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 8779d2b04fad..4a4ef3cb64cb 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2793,6 +2793,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 (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); @@ -2857,6 +2860,7 @@ _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; @@ -2875,13 +2879,32 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) return; if (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) { @@ -2892,12 +2915,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; @@ -2950,10 +2979,37 @@ _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 (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 @@ -2965,7 +3021,6 @@ _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; if (msix_disable == -1 || msix_disable == 0) try_msix = 1; @@ -2999,11 +3054,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) if (ioc->msix_vector_count < ioc->cpu_count) smp_affinity_enable = 0; - if (smp_affinity_enable) - irq_flags |= PCI_IRQ_AFFINITY; - - 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", From 2426f20903ff4ee83cef585b2130ed45adc865d8 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:41 -0400 Subject: [PATCH 122/185] scsi: mpt3sas: Enable interrupt coalescing on high iops Enable interrupt coalescing only on high iops queues. In ioc config page 1, offset 0x14 (ProductSpecific field) is used to determine interrupt coalescing enabled/disabled on per reply descriptor post queue group(8) basis. 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 (i.e. on high iops queues), set bit 0 and 31. This configuration should reset during driver unload or shutdown to the default settings. For this, the driver takes copy of default ioc page 1 and copies back the default or unmodified ioc page1 during unload and shutdown. This means that on next driver load (e.g. if older version driver is loaded by user), current modified changes on ioc page1 won't take effect. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 2 +- drivers/scsi/mpt3sas/mpt3sas_base.c | 16 ++++++ drivers/scsi/mpt3sas/mpt3sas_base.h | 5 ++ drivers/scsi/mpt3sas/mpt3sas_config.c | 71 +++++++++++++++++++++++++++ drivers/scsi/mpt3sas/mpt3sas_scsih.c | 17 ++++++- 5 files changed, 109 insertions(+), 2 deletions(-) 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 4a4ef3cb64cb..1afc76d0fe4e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4439,6 +4439,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) { Mpi2ConfigReply_t mpi_reply; u32 iounit_pg1_flags; + Mpi2IOCPage1_t ioc_pg1; ioc->nvme_abort_timeout = 30; mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); @@ -4471,6 +4472,21 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) else ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO; } + if (ioc->high_iops_queues) { + mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + pr_info( + "%s Enable interrupt coalescing only for first reply queue group(8)\n", + ioc->name); + /* 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 zeroth bit is enabled. + */ + ioc_pg1.ProductSpecific = cpu_to_le32(0x80000001); + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + } mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index f3818e30baed..b5a2071f6e0e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1286,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; @@ -1634,6 +1635,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 b18cbbc0696c..14a1a2793dd5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -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_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 3e93c4ab841b..1f6aa8b19a4d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -9671,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; @@ -9685,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); @@ -9748,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; @@ -9762,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); From ca7e1e9d88a4a89bcdd7da5d81d038199ea96592 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:42 -0400 Subject: [PATCH 123/185] scsi: mpt3sas: Introduce perf_mode module parameter 1. Introduce module parameter perf_mode for only Aero/Sea generation HBAs. 2. Update IOC page1 fields according to performance mode. Below are the performance modes that can be enabled with module parameter perf_mode: 0: Balanced - Few high iops reply queues will be enabled. Interrupt coalescing will be enabled only for these high iops reply descriptor queues. 1: Iops - Interrupt coalescing will be enabled on all reply queues. Coalescing timeout is set to 0x20.This is default value for Aero. 2: Latency - Interrupt coalescing will be enabled on all reply queues. Coalescing timeout is set to 0xA. This is a legacy behavior similar to Ventura & Invader HBA series. Default perf mode set by driver will be balanced mode if the following conditions are met: - CPU vendor = Intel; - Aero controller working in 16GT/s pcie speed Performance mode will be set to latency mode for all other cases. 4k Random Read IO performance numbers on 24 SAS SSD drives for above three permormance modes. Performance data is from Intel Skylake and HGST SS300 (drive model SDLL1DLR400GCCA1). IOPs: ----------------------------------------------------------------------- |perf_mode | qd = 1 | qd = 64 | note | |-------------|--------|---------|------------------------------------- |balanced | 259K | 3061k | Provides max performance numbers | | | | | both on lower QD workload & | | | | | also on higher QD workload | |-------------|--------|---------|------------------------------------- |iops | 220K | 3100k | Provides max performance numbers | | | | | only on higher QD workload. | |-------------|--------|---------|------------------------------------- |latency | 246k | 2226k | Provides good performance numbers | | | | | only on lower QD worklaod. | ----------------------------------------------------------------------- Avarage Latency: ----------------------------------------------------- |perf_mode | qd = 1 | qd = 64 | |-------------|--------------|----------------------| |balanced | 92.05 usec | 501.12 usec | |-------------|--------------|----------------------| |iops | 108.40 usec | 498.10 usec | |-------------|--------------|----------------------| |latency | 97.10 usec | 689.26 usec | ----------------------------------------------------- Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 144 ++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 1afc76d0fe4e..e6377ec07f6c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -103,6 +103,27 @@ 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, 0); +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 - on Intel architecture, default perf_mode is\n\t\t" + " 'balanced' and in others architectures the default mode is 'latency'" + ); + +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); @@ -2959,6 +2980,42 @@ static void _base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, int hba_msix_vector_count) { + enum pci_bus_speed speed = PCI_SPEED_UNKNOWN; + + 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) { + +#if defined(CONFIG_X86) + /* + * Use global variable boot_cpu_data.x86_vendor to + * determine whether the architecture is Intel or not. + */ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) { + ioc->high_iops_queues = 0; + return; + } +#else + ioc->high_iops_queues = 0; + return; +#endif + speed = pcie_get_speed_cap(ioc->pdev); + dev_info(&ioc->pdev->dev, "PCIe device speed is %s\n", + speed == PCIE_SPEED_2_5GT ? "2.5GHz" : + speed == PCIE_SPEED_5_0GT ? "5.0GHz" : + speed == PCIE_SPEED_8_0GT ? "8.0GHz" : + speed == PCIE_SPEED_16_0GT ? "16.0GHz" : + "Unknown"); + + if (speed < PCIE_SPEED_16_0GT) { + ioc->high_iops_queues = 0; + return; + } + } if (!reset_devices && ioc->is_aero_ioc && hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES && @@ -3034,8 +3091,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) 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); - - _base_check_and_enable_high_iops_queues(ioc, ioc->msix_vector_count); + 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); @@ -4430,6 +4488,70 @@ out: kfree(sas_iounit_pg1); } +/** + * _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; + } + 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 @@ -4439,7 +4561,6 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) { Mpi2ConfigReply_t mpi_reply; u32 iounit_pg1_flags; - Mpi2IOCPage1_t ioc_pg1; ioc->nvme_abort_timeout = 30; mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); @@ -4472,21 +4593,6 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) else ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO; } - if (ioc->high_iops_queues) { - mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); - pr_info( - "%s Enable interrupt coalescing only for first reply queue group(8)\n", - ioc->name); - /* 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 zeroth bit is enabled. - */ - ioc_pg1.ProductSpecific = cpu_to_le32(0x80000001); - mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); - } mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); @@ -4513,6 +4619,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); } /** From 895d8860a1a9b13ebddccb76a70faf4c01081699 Mon Sep 17 00:00:00 2001 From: Suganath Prabu S Date: Fri, 31 May 2019 08:14:43 -0400 Subject: [PATCH 124/185] scsi: mpt3sas: Update driver version to 29.100.00.00 Update driver version from 28.100.00.00 to 29.100.00.00 This is equivalent to Phase 10 OOB driver. Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index b5a2071f6e0e..44b8a23d5974 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -76,8 +76,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "28.100.00.00" -#define MPT3SAS_MAJOR_VERSION 28 +#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 From 924a3541eab0d28101baf0831e4315593f06ba4a Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 10 Jun 2019 20:41:41 +0800 Subject: [PATCH 125/185] scsi: libsas: aic94xx: hisi_sas: mvsas: pm8001: Use dev_is_expander() Many times in libsas, and in LLDDs which use libsas, the check for an expander device is re-implemented or open coded. Use dev_is_expander() instead. We rename this from sas_dev_type_is_expander() to not spill so many lines in referencing. Signed-off-by: John Garry Reviewed-by: Jason Yan Reviewed-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/aic94xx/aic94xx_dev.c | 4 +--- drivers/scsi/hisi_sas/hisi_sas.h | 4 ---- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 +++---- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 ++-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 4 ++-- drivers/scsi/isci/remote_device.c | 4 ++-- drivers/scsi/isci/remote_device.h | 5 ----- drivers/scsi/isci/request.c | 2 +- drivers/scsi/isci/task.c | 2 +- drivers/scsi/libsas/sas_discover.c | 5 ++--- drivers/scsi/libsas/sas_expander.c | 29 +++++++++----------------- drivers/scsi/libsas/sas_port.c | 6 +++--- drivers/scsi/mvsas/mv_sas.c | 2 +- drivers/scsi/mvsas/mv_sas.h | 3 --- drivers/scsi/pm8001/pm8001_hwi.c | 4 ++-- drivers/scsi/pm8001/pm8001_sas.c | 2 +- drivers/scsi/pm8001/pm8001_sas.h | 1 - drivers/scsi/pm8001/pm80xx_hwi.c | 4 ++-- include/scsi/libsas.h | 3 +-- 19 files changed, 35 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 33072388ea16..e528a2ce9602 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -187,9 +187,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/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 06f22fb372b1..8657977a2dd4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -66,10 +66,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 diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 256f93e6f89f..90e5d947d8e4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -808,7 +808,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; @@ -1451,7 +1451,7 @@ 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); } @@ -1538,7 +1538,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 */ @@ -1908,7 +1908,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); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b8c0ba778293..7ebd62d2462e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -949,7 +949,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; @@ -2531,7 +2531,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; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index b92aa6b37e1d..b75bf92066a9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -759,7 +759,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; @@ -1358,7 +1358,7 @@ 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(4U << CMD_HDR_CMD_OFF); 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 c552b4b59717..343d24c7e788 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -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; 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/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 2518cecb7edf..abcad097ff2f 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -293,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) { @@ -503,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_expander.c b/drivers/scsi/libsas/sas_expander.c index fd16a3debef4..ecae55f117a3 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1120,8 +1120,7 @@ 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); @@ -1139,8 +1138,7 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev) 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); @@ -1225,8 +1223,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) @@ -1322,8 +1319,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; @@ -1619,8 +1615,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); @@ -1852,7 +1847,7 @@ static int sas_find_bcast_dev(struct domain_device *dev, 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; @@ -1869,8 +1864,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); @@ -1890,8 +1884,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); @@ -1920,8 +1913,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); @@ -1974,8 +1966,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; } diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 11f028a441dd..7c86fd248129 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -54,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]; @@ -179,7 +179,7 @@ static void sas_form_port(struct asd_sas_phy *phy) sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); /* Only insert a revalidate event after initial discovery */ - if (port_dev && sas_dev_type_is_expander(port_dev->dev_type)) { + 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; @@ -248,7 +248,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone) spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); /* Only insert revalidate event if the port still has members */ - if (port->port && dev && sas_dev_type_is_expander(dev->dev_type)) { + if (port->port && dev && dev_is_expander(dev->dev_type)) { struct expander_device *ex_dev = &dev->ex_dev; ex_dev->ex_change_count = -1; diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index e933c65d8e0b..0ee688f52990 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1209,7 +1209,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; diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 080676c1c9e5..b391c03fe5f5 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -66,9 +66,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/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 109effd3557d..68a8217032d0 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2356,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++) @@ -4560,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; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 3de57c5a3299..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; diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index ac6d8e3f22de..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) \ diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 301de40eb708..1128d86d241a 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -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++) @@ -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; diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 901355a1bc53..a8565a87291d 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -207,8 +207,7 @@ struct sas_work { struct work_struct work; }; -/* Lots of code duplicates this in the SCSI tree, which can be factored out */ -static inline bool sas_dev_type_is_expander(enum sas_device_type type) +static inline bool dev_is_expander(enum sas_device_type type) { return type == SAS_EDGE_EXPANDER_DEVICE || type == SAS_FANOUT_EXPANDER_DEVICE; From 6ea3b189f7704f0881815b414a20f36a2529030c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 11 Jun 2019 10:02:19 -0500 Subject: [PATCH 126/185] scsi: mpt3sas: Mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warning: drivers/scsi/mpt3sas/mpt3sas_base.c: In function _base_update_ioc_page1_inlinewith_perf_mode : drivers/scsi/mpt3sas/mpt3sas_base.c:4510:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (ioc->high_iops_queues) { ^ drivers/scsi/mpt3sas/mpt3sas_base.c:4530:2: note: here case MPT_PERF_MODE_LATENCY: ^~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enable -Wimplicit-fallthrough. Fixes: 30cb97023f38 ("scsi: mpt3sas: Introduce perf_mode module parameter") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index e6377ec07f6c..9fefcd1e9c97 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4527,6 +4527,7 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "performance mode: balanced\n"); return; } + /* Fall through */ case MPT_PERF_MODE_LATENCY: /* * Enable interrupt coalescing on all reply queues From adfbd028e155fca3bbe33d458f2f27cb657e5792 Mon Sep 17 00:00:00 2001 From: Branden Bonaby Date: Fri, 14 Jun 2019 19:48:22 -0400 Subject: [PATCH 127/185] scsi: storvsc: Add ability to change scsi queue depth Adding functionality to allow the SCSI queue depth to be changed by utilizing the "scsi_change_queue_depth" function. [mkp: checkpatch] Signed-off-by: Branden Bonaby Reviewed-by: Michael Kelley Reviewed-by: K. Y. Srinivasan Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 8472de1007ff..5b6c0f88da59 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -387,6 +387,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 +1712,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 +1919,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); From 22c2f35f49d474fa093b227253941980886d7b1b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 16 Jun 2019 09:02:20 +0200 Subject: [PATCH 128/185] scsi: tcmu: Simplify tcmu_update_uio_info() Use 'kasprintf()' instead of: - snprintf(NULL, 0... - kmalloc(... - snprintf(... This is less verbose and saves 7 bytes (i.e. the space for '/(null)') if 'udev->dev_config' is NULL. Signed-off-by: Christophe JAILLET Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 40b29ca5a98d..9dbd0db64328 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1836,21 +1836,19 @@ static int tcmu_update_uio_info(struct tcmu_dev *udev) { struct tcmu_hba *hba = udev->hba->hba_ptr; struct uio_info *info; - size_t size, used; char *str; info = &udev->uio_info; - size = snprintf(NULL, 0, "tcm-user/%u/%s/%s", hba->host_id, udev->name, - udev->dev_config); - size += 1; /* for \0 */ - str = kmalloc(size, GFP_KERNEL); + + if (udev->dev_config[0]) + str = kasprintf(GFP_KERNEL, "tcm-user/%u/%s/%s", hba->host_id, + udev->name, udev->dev_config); + else + str = kasprintf(GFP_KERNEL, "tcm-user/%u/%s", hba->host_id, + udev->name); if (!str) return -ENOMEM; - used = snprintf(str, size, "tcm-user/%u/%s", hba->host_id, udev->name); - if (udev->dev_config[0]) - snprintf(str + used, size - used, "/%s", udev->dev_config); - /* If the old string exists, free it */ kfree(info->name); info->name = str; From 152e30fc53cb110b3d51c58ba271ae452f1d2edb Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Mon, 17 Jun 2019 18:46:26 +0530 Subject: [PATCH 129/185] scsi: cxgb4i: add support for IEEE_8021QAZ_APP_SEL_STREAM selector IEEE_8021QAZ_APP_SEL_STREAM is a valid selector for iSCSI connections, so add code to use IEEE_8021QAZ_APP_SEL_STREAM selector to get priority mask. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 124f3345420f..0e767e65f04f 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -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); @@ -2251,7 +2255,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; From ac88c1f6730e73771dc36b9fd83804e7aa15941a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 17 Jun 2019 08:18:18 -0700 Subject: [PATCH 130/185] scsi: Restrict user space SCSI device state changes to "running" and "offline" The ability to modify the SCSI device state was introduced by commit 638127e579a4 ("[PATCH] Fix error handler offline behaviour"; v2.6.12). That same commit introduced the following device states: { SDEV_CREATED, "created" }, { SDEV_RUNNING, "running" }, { SDEV_CANCEL, "cancel" }, { SDEV_DEL, "deleted" }, { SDEV_QUIESCE, "quiesce" }, { SDEV_OFFLINE, "offline" }, The SDEV_BLOCK state was introduced later to avoid that an FC cable pull would immediately result in an I/O error (commit 1094e682310e; "[PATCH] suspending I/Os to a device"; v2.6.12). That same patch introduced the ability to set the SDEV_BLOCK state from user space. I'm not sure whether that ability was introduced on purpose or accidentally. Since there is agreement that only writing "running" or "offline" into the SCSI sysfs device state attribute makes sense, restrict sysfs writes to these values. This patch makes sure that SDEV_BLOCK is only used for its original purpose, namely to allow transport drivers and LLDs to block further .queuecommand() calls while transport layer or adapter recovery is in progress. Note: a web search for "/sys/class/scsi_device" AND "device/state" revealed several storage configuration guides. The instructions I found in these guides tell users to write the value "running" or "offline" in the SCSI device state sysfs attribute and no other values. [mkp: typo] Cc: Christoph Hellwig Cc: Ming Lei Cc: Hannes Reinecke Cc: Johannes Thumshirn Cc: James Smart Cc: Ewan D. Milne Cc: Laurence Oberman Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_sysfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index ff0aea7ac87f..8b4fc2d4ba7b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -767,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); From bbe9fb0d04b96dda1fd7bd973e094004978b2166 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 17 Jun 2019 08:18:19 -0700 Subject: [PATCH 131/185] scsi: Avoid that .queuecommand() gets called for a blocked SCSI device Several SCSI transport and LLD drivers surround code that does not tolerate concurrent calls of .queuecommand() with scsi_target_block() / scsi_target_unblock(). These last two functions use blk_mq_quiesce_queue() / blk_mq_unquiesce_queue() for scsi-mq request queues to prevent concurrent .queuecommand() calls. However, that is not sufficient to prevent .queuecommand() calls from scsi_send_eh_cmnd(). Hence surround the .queuecommand() call from the SCSI error handler with code that avoids that .queuecommand() gets called in the blocked state. Note: converting the .queuecommand() call in scsi_send_eh_cmnd() into code that calls blk_get_request() + blk_execute_rq() is not an option since scsi_send_eh_cmnd() must be able to make forward progress even if all requests have been allocated. Cc: Ming Lei Cc: Hannes Reinecke Cc: Johannes Thumshirn Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 26 ++++++++++++++++++++++++-- drivers/scsi/scsi_lib.c | 4 ---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f490994374f6..9f16304150b1 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1055,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; @@ -1066,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); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b1b1a1aaa353..6c84edc53f05 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2616,10 +2616,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) { From fd56141244066a6a21ef458670071c58b6402035 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 17 Jun 2019 08:18:20 -0700 Subject: [PATCH 132/185] scsi: RDMA/srp: Fix a sleep-in-invalid-context bug The previous patch guarantees that srp_queuecommand() does not get invoked while reconnecting occurs. Hence remove the code from srp_queuecommand() that prevents command queueing while reconnecting. This patch avoids that the following can appear in the kernel log: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:747 in_atomic(): 1, irqs_disabled(): 0, pid: 5600, name: scsi_eh_9 1 lock held by scsi_eh_9/5600: #0: (rcu_read_lock){....}, at: [<00000000cbb798c7>] __blk_mq_run_hw_queue+0xf1/0x1e0 Preemption disabled at: [<00000000139badf2>] __blk_mq_delay_run_hw_queue+0x78/0xf0 CPU: 9 PID: 5600 Comm: scsi_eh_9 Tainted: G W 4.15.0-rc4-dbg+ #1 Hardware name: Dell Inc. PowerEdge R720/0VWT90, BIOS 2.5.4 01/22/2016 Call Trace: dump_stack+0x67/0x99 ___might_sleep+0x16a/0x250 [ib_srp] __mutex_lock+0x46/0x9d0 srp_queuecommand+0x356/0x420 [ib_srp] scsi_dispatch_cmd+0xf6/0x3f0 scsi_queue_rq+0x4a8/0x5f0 blk_mq_dispatch_rq_list+0x73/0x440 blk_mq_sched_dispatch_requests+0x109/0x1a0 __blk_mq_run_hw_queue+0x131/0x1e0 __blk_mq_delay_run_hw_queue+0x9a/0xf0 blk_mq_run_hw_queue+0xc0/0x1e0 blk_mq_start_hw_queues+0x2c/0x40 scsi_run_queue+0x18e/0x2d0 scsi_run_host_queues+0x22/0x40 scsi_error_handler+0x18d/0x5f0 kthread+0x11c/0x140 ret_from_fork+0x24/0x30 Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Laurence Oberman Cc: Jason Gunthorpe Cc: Leon Romanovsky Cc: Doug Ledford Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/infiniband/ulp/srp/ib_srp.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index be9ddcad8f28..b7c5a35f7daa 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2338,7 +2338,6 @@ static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) { struct srp_target_port *target = host_to_target(shost); - struct srp_rport *rport = target->rport; struct srp_rdma_ch *ch; struct srp_request *req; struct srp_iu *iu; @@ -2348,16 +2347,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) u32 tag; u16 idx; int len, ret; - const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler; - - /* - * The SCSI EH thread is the only context from which srp_queuecommand() - * can get invoked for blocked devices (SDEV_BLOCK / - * SDEV_CREATED_BLOCK). Avoid racing with srp_reconnect_rport() by - * locking the rport mutex if invoked from inside the SCSI EH. - */ - if (in_scsi_eh) - mutex_lock(&rport->mutex); scmnd->result = srp_chkready(target->rport); if (unlikely(scmnd->result)) @@ -2426,13 +2415,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) goto err_unmap; } - ret = 0; - -unlock_rport: - if (in_scsi_eh) - mutex_unlock(&rport->mutex); - - return ret; + return 0; err_unmap: srp_unmap_data(scmnd, ch, req); @@ -2454,7 +2437,7 @@ err: ret = SCSI_MLQUEUE_HOST_BUSY; } - goto unlock_rport; + return ret; } /* From 5da1faa07b7d6975a6d0266eab391f92a16aeb09 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 17 Jun 2019 19:50:12 +0200 Subject: [PATCH 133/185] scsi: wd719x: Fix resets and aborts Host reset oopses because it calls wd719x_chip_init, which calls request_firmware, under a spinlock. Stop the RISC first, then flush active SCBs under a spinlock. Finally call wd719x_chip_init unlocked. Also found and fixed more bugs during tests: Affected active SCBs were not flushed during abort, bus and device reset. This caused problems in a following host reset (hang or oops). Device and bus reset failed under load because the result of the reset command is WD719X_SUE_TERM or WD719X_SUE_RESET. Don't treat these codes as error in wd719x_wait_done. wd719x_direct_cmd for RESET/ABORT commands didn't work properly, causing timeouts. Looks like it was caused by the WD719X_DISABLE_INT bit. Not setting it for RESET/ABORT commands seems to fix the probem. Also lower the log level of the corresponding "direct command completed" message to debug. Unfortunately, my documentation is missing some pages, including page 67 (SPIDER67.gif) about resets :( Reported-by: Hariprasad Kelam Signed-off-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- drivers/scsi/wd719x.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index e3310e9488d2..2b44b0be2e00 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -107,8 +107,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 +134,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 +473,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 +486,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 +494,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 +522,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 +690,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: From 25fcf94a2fa89dd3e73e965ebb0b38a2a4f72aa4 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 134/185] Revert "scsi: ncr5380: Increase register polling limit" This reverts commit 4822827a69d7cd3bc5a07b7637484ebd2cf88db6. The purpose of that commit was to suppress a timeout warning message which appeared to be caused by target latency. But suppressing the warning is undesirable as the warning may indicate a messed up transfer count. Another problem with that commit is that 15 ms is too long to keep interrupts disabled as interrupt latency can cause system clock drift and other problems. Cc: Michael Schmitz Cc: stable@vger.kernel.org Fixes: 4822827a69d7 ("scsi: ncr5380: Increase register polling limit") Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) { From 57f31326518e98ee4cabf9a04efe00ed57c54147 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 135/185] scsi: NCR5380: Always re-enable reselection interrupt The reselection interrupt gets disabled during selection and must be re-enabled when hostdata->connected becomes NULL. If it isn't re-enabled a disconnected command may time-out or the target may wedge the bus while trying to reselect the host. This can happen after a command is aborted. Fix this by enabling the reselection interrupt in NCR5380_main() after calls to NCR5380_select() and NCR5380_information_transfer() return. Cc: Michael Schmitz Cc: stable@vger.kernel.org # v4.9+ Fixes: 8b00c3d5d40d ("ncr5380: Implement new eh_abort_handler") Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index fe0535affc14..08e3ea8159b3 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -709,6 +709,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(); @@ -1110,8 +1112,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; } @@ -1119,7 +1119,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) @@ -1157,7 +1156,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) { @@ -1826,9 +1824,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: @@ -1860,8 +1855,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 @@ -1964,7 +1957,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; From f9dfed1c785734b95b08d67600e05d2092508ab0 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 136/185] scsi: NCR5380: Handle PDMA failure reliably A PDMA error is handled in the core driver by setting the device's 'borken' flag and aborting the command. Unfortunately, do_abort() is not dependable. Perform a SCSI bus reset instead, to make sure that the command fails and gets retried. Cc: Michael Schmitz Cc: stable@vger.kernel.org # v4.20+ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 08e3ea8159b3..d9fa9cf2fd8b 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1761,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 From 7398cee4c3e6aea1ba07a6449e5533ecd0b92cdd Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 137/185] scsi: mac_scsi: Increase PIO/PDMA transfer length threshold Some targets introduce delays when handshaking the response to certain commands. For example, a disk may send a 96-byte response to an INQUIRY command (or a 24-byte response to a MODE SENSE command) too slowly. Apparently the first 12 or 14 bytes are handshaked okay but then the system bus error timeout is reached while transferring the next word. Since the scsi bus phase hasn't changed, the driver then sets the target borken flag to prevent further PDMA transfers. The driver also logs the warning, "switching to slow handshake". Raise the PDMA threshold to 512 bytes so that PIO transfers will be used for these commands. This default is sufficiently low that PDMA will still be used for READ and WRITE commands. The existing threshold (16 bytes) was chosen more or less at random. However, best performance requires the threshold to be as low as possible. Those systems that don't need the PIO workaround at all may benefit from mac_scsi.setup_use_pdma=1 Cc: Michael Schmitz Cc: stable@vger.kernel.org # v4.14+ Fixes: 3a0f64bfa907 ("mac_scsi: Fix pseudo DMA implementation") Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 8b4b5b1a13d7..ba1afcaadae8 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -52,7 +52,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); @@ -305,7 +305,7 @@ 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; From 78ff751f8e6a9446e9fb26b2bff0b8d3f8974cbd Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 138/185] scsi: mac_scsi: Fix pseudo DMA implementation, take 2 A system bus error during a PDMA transfer can mess up the calculation of the transfer residual (the PDMA handshaking hardware lacks a byte counter). This results in data corruption. The algorithm in this patch anticipates a bus error by starting each transfer with a MOVE.B instruction. If a bus error is caught the transfer will be retried. If a bus error is caught later in the transfer (for a MOVE.W instruction) the transfer gets failed and subsequent requests for that target will use PIO instead of PDMA. This avoids the "!REQ and !ACK" error so the severity level of that message is reduced to KERN_DEBUG. Cc: Michael Schmitz Cc: Geert Uytterhoeven Cc: stable@vger.kernel.org # v4.14+ Fixes: 3a0f64bfa907 ("mac_scsi: Fix pseudo DMA implementation") Signed-off-by: Finn Thain Reported-by: Chris Jones Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_scsi.c | 369 +++++++++++++++++++++++----------------- 1 file changed, 217 insertions(+), 152 deletions(-) diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index ba1afcaadae8..27364b71e833 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -3,6 +3,8 @@ * * Copyright 1998, Michael Schmitz * + * Copyright 2019 Finn Thain + * * derived in part from: */ /* @@ -11,6 +13,7 @@ * Copyright 1995, Russell King */ +#include #include #include #include @@ -89,101 +92,217 @@ static int __init mac_scsi_setup(char *str) __setup("mac5380=", mac_scsi_setup); #endif /* !MODULE */ -/* Pseudo DMA asm originally by Ove Edlund */ +/* + * 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 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") +#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; +} 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; + + 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; - 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) + if (bytes > 0) { + d += bytes; + hostdata->pdma_residual -= bytes; + } + + if (hostdata->pdma_residual == 0) return 0; - /* 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; + 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; + return -1; } scmd_printk(KERN_ERR, hostdata->connected, @@ -192,93 +311,27 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, return -1; } - -#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; + + 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; + bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512)); - /* 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; + 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) @@ -287,17 +340,29 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, return 0; } + 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)) + return 0; + + 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; + return -1; } scmd_printk(KERN_ERR, hostdata->connected, "%s: phase mismatch or !DRQ\n", __func__); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - return -1; } From 8fb9a64eb6e6fe502187c154434729871d9e5578 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 139/185] scsi: mac_scsi: Enable PDMA on Mac IIfx Add support for Apple's custom "SCSI DMA" chip. This patch doesn't make use of its DMA capability. Just the PDMA capability is sufficient to improve sequential read throughput by a factor of 5. Cc: Michael Schmitz Cc: Joshua Thompson Cc: Geert Uytterhoeven Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Acked-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- arch/m68k/mac/config.c | 10 +++++++-- drivers/scsi/mac_scsi.c | 47 ++++++++++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 11be08f4f750..205ac75da13d 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -911,6 +911,10 @@ static const struct resource mac_scsi_iifx_rsrc[] __initconst = { .flags = IORESOURCE_MEM, .start = 0x50008000, .end = 0x50009FFF, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50008000, + .end = 0x50009FFF, }, }; @@ -1012,10 +1016,12 @@ int __init mac_platform_init(void) case MAC_SCSI_IIFX: /* Addresses from The Guide to Mac Family Hardware. * $5000 8000 - $5000 9FFF: SCSI DMA + * $5000 A000 - $5000 BFFF: Alternate SCSI * $5000 C000 - $5000 DFFF: Alternate SCSI (DMA) * $5000 E000 - $5000 FFFF: Alternate SCSI (Hsk) - * The SCSI DMA custom IC embeds the 53C80 core. mac_scsi does - * not make use of its DMA or hardware handshaking logic. + * The A/UX header file sys/uconfig.h says $50F0 8000. + * The "SCSI DMA" custom IC embeds the 53C80 core and + * supports Programmed IO, DMA and PDMA (hardware handshake). */ platform_device_register_simple("mac_scsi", 0, mac_scsi_iifx_rsrc, ARRAY_SIZE(mac_scsi_iifx_rsrc)); diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 27364b71e833..8fbec1768bbf 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -262,11 +263,22 @@ 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 result = 0; hostdata->pdma_residual = len; @@ -275,6 +287,10 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { int bytes; + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | + CTRL_INTERRUPTS_ENABLE); + bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512)); if (bytes > 0) { @@ -283,7 +299,7 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, } if (hostdata->pdma_residual == 0) - return 0; + goto out; if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, BUS_AND_STATUS_REG, BASR_ACK, @@ -291,7 +307,7 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, 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); @@ -302,13 +318,18 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, "%s: bus error (%d/%d)\n", __func__, d - dst, len); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - return -1; + 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 inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, @@ -316,6 +337,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, { unsigned char *s = src; u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); + int result = 0; hostdata->pdma_residual = len; @@ -324,6 +346,10 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { int bytes; + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | + CTRL_INTERRUPTS_ENABLE); + bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512)); if (bytes > 0) { @@ -337,7 +363,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, TCR_LAST_BYTE_SENT, HZ / 64) < 0) scmd_printk(KERN_ERR, hostdata->connected, "%s: Last Byte Sent timeout\n", __func__); - return 0; + goto out; } if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, @@ -346,7 +372,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, 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); @@ -357,13 +383,18 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, "%s: bus error (%d/%d)\n", __func__, s - src, len); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - return -1; + 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, From 7c1f3e3447a13a91e95fff6bac7312858c90b0cf Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 9 Jun 2019 11:19:11 +1000 Subject: [PATCH 140/185] scsi: mac_scsi: Treat Last Byte Sent time-out as failure A system bus error during a PDMA send operation can result in bytes being lost. Theoretically that could cause the target to remain in DATA OUT phase and the initiator (expecting a phase change) would time-out waiting for the Last Byte Sent flag. Should that happen, fail the transfer so the core driver will stop using PDMA with this target. Cc: Michael Schmitz Signed-off-by: Finn Thain Tested-by: Stan Johnson Tested-by: Michael Schmitz Signed-off-by: Martin K. Petersen --- drivers/scsi/mac_scsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 8fbec1768bbf..658a719cfcba 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -360,9 +360,12 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, 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__); + result = -1; + } goto out; } From e58ed5002f17ed027272088fa0d3e57fa81bd8d4 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 7 Jun 2019 13:40:53 -0500 Subject: [PATCH 141/185] scsi: megaraid_sas: Use struct_size() helper One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct MR_PD_CFG_SEQ_NUM_SYNC { ... struct MR_PD_CFG_SEQ seq[1]; } __packed; Make use of the struct_size() helper instead of an open-coded version in order to avoid any potential type mistakes. So, replace the following form: sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1)) with: struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1) This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 2edb08247efa..8a7ac5c09c53 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1203,7 +1203,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; @@ -1212,9 +1212,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) { From e1a7752ca7b150b2acd2560ca3a9eae1287d0201 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 17 Jun 2019 12:54:54 +0100 Subject: [PATCH 142/185] scsi: ufs-qcom: Add support for platforms booting ACPI New Qualcomm AArch64 based laptops are now available which use UFS as their primary data storage medium. These devices are supplied with ACPI support out of the box. This patch ensures the Qualcomm UFS driver will be bound when the "QCOM24A5" H/W device is advertised as present. Signed-off-by: Lee Jones Reviewed-by: Ard Biesheuvel Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index ea7219407309..61a5c6ea4edf 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -12,6 +12,7 @@ * */ +#include #include #include #include @@ -170,6 +171,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) @@ -1136,9 +1140,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); @@ -1608,6 +1616,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, @@ -1624,6 +1640,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); From ab9f5adb8d14a59fd5062ac1d880c5d10bb75959 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Fri, 14 Jun 2019 16:41:43 +0200 Subject: [PATCH 143/185] scsi: mpt3sas: make driver options visible in sys Support is easier with all driver parameters visible in sysfs. Also I've replaced a constant with an octal permission. Signed-off-by: Tomas Henzl Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 14 +++++++------- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 9fefcd1e9c97..cae74418015d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -74,28 +74,28 @@ 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, 0); +module_param(irqpoll_weight, int, 0444); MODULE_PARM_DESC(irqpoll_weight, "irq poll weight (default= one fourth of HBA queue depth)"); @@ -104,7 +104,7 @@ 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, 0); +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" diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 1f6aa8b19a4d..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 "); From c9df1442725953591fd0d351cf0c95dc4b6cc9e5 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Fri, 14 Jun 2019 16:41:44 +0200 Subject: [PATCH 144/185] scsi: mpt3sas: use DEVICE_ATTR_{RO, RW} Use existing macros. No functional change. [mkp: typo] Signed-off-by: Tomas Henzl Acked-by: Suganath Prabu Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 210 +++++++++++++---------------- 1 file changed, 97 insertions(+), 113 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index b5cae58219b9..d4ecfbbe738c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -2457,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 @@ -2465,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); @@ -2477,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 @@ -2488,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); @@ -2502,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 @@ -2513,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); @@ -2522,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 @@ -2533,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); @@ -2541,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 @@ -2552,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); @@ -2561,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 @@ -2573,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); @@ -2582,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 @@ -2594,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); @@ -2602,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 @@ -2613,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); @@ -2621,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 @@ -2632,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); @@ -2640,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 @@ -2654,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); @@ -2662,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 @@ -2676,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); @@ -2684,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 @@ -2697,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); @@ -2705,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 @@ -2718,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) { @@ -2728,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 @@ -2740,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); @@ -2749,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); @@ -2764,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 @@ -2777,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); @@ -2786,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); @@ -2801,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 @@ -2815,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); @@ -2823,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 @@ -2836,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; @@ -2851,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 @@ -2865,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); @@ -2927,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; @@ -2940,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 @@ -2948,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); @@ -2980,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 @@ -2996,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); @@ -3028,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); @@ -3041,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 @@ -3058,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); @@ -3076,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); @@ -3126,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 @@ -3141,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) { @@ -3158,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 @@ -3167,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) { @@ -3186,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 @@ -3199,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); @@ -3215,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 @@ -3224,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) { @@ -3243,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 @@ -3256,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); @@ -3272,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 @@ -3281,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); @@ -3299,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 @@ -3312,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); @@ -3328,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 @@ -3337,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); @@ -3356,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 ****************************/ @@ -3395,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 @@ -3405,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); @@ -3414,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 @@ -3427,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); @@ -3436,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 @@ -3447,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); @@ -3458,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) { @@ -3475,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, From 62b52c8ce9d4b7666e293b95bc511cbcabeebe7f Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Wed, 19 Jun 2019 15:52:19 +0800 Subject: [PATCH 145/185] scsi: virtio_scsi: remove unused 'affinity_hint_set' The 'affinity_hint_set' is not used any longer since commit 0d9f0a52c8b9 ("virtio_scsi: use virtio IRQ affinity"). Signed-off-by: Dongli Zhang Acked-by: Paolo Bonzini Signed-off-by: Martin K. Petersen --- drivers/scsi/virtio_scsi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index c47d38bca948..56da8c9d1cc9 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -77,9 +77,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 */ From c870d65fe3084193113ec622049b6906b899366c Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Sun, 23 Jun 2019 17:38:39 +0000 Subject: [PATCH 146/185] scsi: ufs-bsg: fix typo in ufs_bsg_request Correct dev_dbg to dev_err, so as to print out the error information in case of DME command failed. Signed-off-by: Bean Huo Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs_bsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index 869e71f861d6..f420d6f8d84c 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); From b13a3539eb2affcb8833c189d68d6a4b99c41f6e Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Sun, 23 Jun 2019 17:38:56 +0000 Subject: [PATCH 147/185] scsi: ufs-bsg: complete ufs-bsg job only if no error In the case of UPIU/DME request execution failed in UFS device, ufs_bsg_request() will complete the failed bsg job by calling bsg_job_done(). Meanwhile, it returns this error status to blk-mq layer, then triggers blk-mq completing this request again, this will cause the following panic. Call trace: ll_sc___cmpxchg_case_acq_32+0x4/0x20 complete+0x28/0x70 blk_end_sync_rq+0x24/0x30 blk_mq_end_request+0xb8/0x118 bsg_job_put+0x4c/0x58 bsg_complete+0x20/0x30 blk_done_softirq+0xb4/0xe8 do_softirq+0x154/0x3f0 run_ksoftirqd+0x4c/0x68 smpboot_thread_fn+0x22c/0x268 kthread+0x130/0x138 ret_from_fork+0x10/0x1c Code: f84107fe d65f03c0 d503201f f9800011 (885ffc10) ---[ end trace d92825bff6326e66 ]--- Kernel panic - not syncing: Fatal exception in interrupt This patch is to fix this issue. The solution is to complete the ufs-bsg job only if no error happened. [mkp: commit description tweak] Fixes: df032bf27a41 (scsi: ufs: Add a bsg endpoint that supports UPIUs) Signed-off-by: Bean Huo Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs_bsg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index f420d6f8d84c..a9344eb4e047 100644 --- a/drivers/scsi/ufs/ufs_bsg.c +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -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; } From 8c09d75276971da6f98871a1bb4a336b96728bba Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 21 Jun 2019 15:19:42 +0300 Subject: [PATCH 148/185] scsi: ufshdc-pci: Add Intel PCI IDs for EHL Add more Intel PCI IDs. Signed-off-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd-pci.c | 2 ++ 1 file changed, 2 insertions(+) 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 */ }; From 4adb451c8d1656e28a9ec472ccbdc4463205424a Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Mon, 24 Jun 2019 01:29:55 -0700 Subject: [PATCH 149/185] scsi: bnx2fc: Redo setting source FCoE MAC For bnx2fc, the source FCoE MAC is stored in the fcoe_port struct in the data_src_mac field. Currently this is set in fcoe_ctlr_recv_flogi which ends up setting it by simply using fc_fcoe_set_mac() which only uses the default FCF-MAC. We still want to store the source FCoE MAC in port->data_src_mac but we want to snoop the FLOGI response payload so as to set it in the following method: 1. If a granted_mac is found, use that. 2. If not granted_mac is there but there is a FCF-MAP from the FCF then create the MAC from the FCF-MAP and the destination ID from the frame. 3. If there is no FCF-MAP the use the spec. default FCF-MAP and the destination ID from the frame. Signed-off-by: Chad Dupuis Signed-off-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_els.c | 56 +++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 76e65a32f38c..8de5b70f6727 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -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); } From a92ac6ee7980f3c139910d0d0a079802363818cb Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Mon, 24 Jun 2019 01:29:56 -0700 Subject: [PATCH 150/185] scsi: bnx2fc: Only put reference to io_req in bnx2fc_abts_cleanup if cleanup times out In certain tests where the SCSI error handler issues an abort that is already outstanding, we will cleanup the command so that the SCSI error handler can proceed. In some of these cases we were seeing a command mismatch: kernel: scsi host2: bnx2fc: xid:0x42b eh_abort - refcnt = 2 kernel: bnx2fc: eh_abort: io_req (xid = 0x42b) already in abts processing kernel: scsi host2: bnx2fc: xid:0x42b Entered bnx2fc_initiate_cleanup kernel: scsi host2: bnx2fc: xid:0x42b CLEANUP io_req xid = 0x80b kernel: scsi host2: bnx2fc: xid:0x80b cq_compl- cleanup resp rcvd kernel: scsi host2: bnx2fc: xid:0x42b complete - rx_state = 9 kernel: scsi host2: bnx2fc: xid:0x42b Entered process_cleanup_compl refcnt = 2, cmd_type = 1 kernel: scsi host2: bnx2fc: xid:0x42b scsi_done. err_code = 0x7 kernel: scsi host2: bnx2fc: xid:0x42b sc=ffff8807f93dfb80, result=0x7, retries=0, allowed=5 kernel: ------------[ cut here ]------------ kernel: WARNING: at /root/rpmbuild/BUILD/netxtreme2-7.14.43/obj/default/bnx2fc-2.12.1/driver/bnx2fc_io.c:1347 bnx2fc_eh_abort+0x56f/0x680 [bnx2fc]() kernel: xid=0x42b refcount=-1 kernel: Modules linked in: kernel: nls_utf8 isofs sr_mod cdrom tcp_lp dm_round_robin xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack ipt_REJECT nf_reject_ipv4 tun bridge ebtable_filter ebtables fuse ip6table_filter ip6_tables iptable_filter bnx2fc(OE) cnic(OE) uio fcoe libfcoe 8021q libfc garp mrp scsi_transport_fc stp llc scsi_tgt vfat fat dm_service_time intel_powerclamp coretemp intel_rapl iosf_mbi kvm_intel kvm irqbypass crc32_pclmul ghash_clmulni_intel aesni_intel lrw gf128mul glue_helper ablk_helper cryptd ses enclosure ipmi_ssif i2c_core hpilo hpwdt wmi sg ipmi_devintf pcspkr ipmi_si ipmi_msghandler shpchp acpi_power_meter dm_multipath nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs sd_mod crc_t10dif kernel: crct10dif_generic bnx2x(OE) crct10dif_pclmul crct10dif_common crc32c_intel mdio ptp pps_core libcrc32c smartpqi scsi_transport_sas fjes uas usb_storage dm_mirror dm_region_hash dm_log dm_mod kernel: CPU: 9 PID: 2012 Comm: scsi_eh_2 Tainted: G W OE ------------ 3.10.0-514.el7.x86_64 #1 kernel: Hardware name: HPE Synergy 480 Gen10/Synergy 480 Gen10 Compute Module, BIOS I42 03/21/2018 kernel: ffff8807f25a3d98 0000000015e7fa0c ffff8807f25a3d50 ffffffff81685eac kernel: ffff8807f25a3d88 ffffffff81085820 ffff8807f8e39000 ffff880801ff7468 kernel: ffff880801ff7610 0000000000002002 ffff8807f8e39014 ffff8807f25a3df0 kernel: Call Trace: kernel: [] dump_stack+0x19/0x1b kernel: [] warn_slowpath_common+0x70/0xb0 kernel: [] warn_slowpath_fmt+0x5c/0x80 kernel: [] ? _raw_spin_lock_bh+0x12/0x50 kernel: [] bnx2fc_eh_abort+0x56f/0x680 [bnx2fc] kernel: [] scsi_error_handler+0x59f/0x8b0 kernel: [] ? scsi_eh_get_sense+0x250/0x250 kernel: [] kthread+0xcf/0xe0 kernel: [] ? kthread_create_on_node+0x140/0x140 kernel: [] ret_from_fork+0x58/0x90 kernel: [] ? kthread_create_on_node+0x140/0x140 kernel: ---[ end trace 42deb88f2032b111 ]--- The reason that there was a mismatch is that the SCSI command is actual returned from the cleanup handler. In previous testing, the type of cleanup notification we'd get from the CQE did not trigger the code that returned the SCSI command. To overcome the previous behavior we would put a reference in bnx2fc_abts_cleanup() to account for the SCSI command. However, in cases where the SCSI command is actually off, we end up with an extra put. The fix for this is to only take the extra put in bnx2fc_abts_cleanup if the completion for the cleanup times out. Signed-off-by: Chad Dupuis Signed-off-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_io.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 8def63c0755f..578ff53a4e8d 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1097,16 +1097,16 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) time_left = wait_for_completion_timeout(&io_req->tm_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 SUCCESS; From 0e0fcef97201712894959568c24c08fd7542a2ec Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Mon, 24 Jun 2019 01:29:57 -0700 Subject: [PATCH 151/185] scsi: bnx2fc: Separate out completion flags and variables for abort and cleanup Separate out abort and cleanup flag and completion, to have better understaning of what is getting processed. Signed-off-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc.h | 6 ++-- drivers/scsi/bnx2fc/bnx2fc_io.c | 59 +++++++++++++++++--------------- drivers/scsi/bnx2fc/bnx2fc_tgt.c | 10 +++--- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 901a31632493..5d7e21a818c5 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -433,8 +433,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; diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 578ff53a4e8d..88c392ba80a9 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); } @@ -1085,7 +1086,8 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) struct bnx2fc_rport *tgt = io_req->tgt; 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); @@ -1094,9 +1096,8 @@ 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) { BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n", __func__); @@ -1109,6 +1110,7 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) } spin_lock_bh(&tgt->tgt_lock); + io_req->wait_for_cleanup_comp = 0; return SUCCESS; } @@ -1197,7 +1199,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) " @@ -1225,26 +1228,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; @@ -1321,8 +1326,8 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, kref_read(&io_req->refcount), io_req->cmd_type); 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, @@ -1390,10 +1395,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 @@ -1577,9 +1582,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); } } @@ -1926,10 +1931,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); } From 25ad7394c7783a5bc73f7a930bda3a7a7f3195cb Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Mon, 24 Jun 2019 01:29:58 -0700 Subject: [PATCH 152/185] scsi: bnx2fc: Do not allow both a cleanup completion and abort completion for the same request If firmware sends either cleanup or abort completion, it means other won't be sent. Clean out flags for other as well. Signed-off-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc.h | 1 + drivers/scsi/bnx2fc/bnx2fc_io.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 5d7e21a818c5..14cc6921a1b8 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -457,6 +457,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_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 88c392ba80a9..d7eb5e16efd3 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1048,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); @@ -1324,6 +1327,25 @@ 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_cleanup_comp) @@ -1351,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)) From 3c97b569505f0d467a7fd544b05f1e122c08db67 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Mon, 24 Jun 2019 01:29:59 -0700 Subject: [PATCH 153/185] scsi: bnx2fc: Limit the IO size according to the FW capability - Reduce the sg_tablesize to 255. - Reduce the MAX BDs firmware can handle to 255. - Return IO to ML if BD goes more then 255 after split. - Correct the size of each BD split to 0xffff. Signed-off-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc.h | 5 +++-- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 3 ++- drivers/scsi/bnx2fc/bnx2fc_io.c | 11 +++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 14cc6921a1b8..170abe90007a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -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 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_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index d7eb5e16efd3..9e50e5b53763 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1660,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. @@ -1707,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; } From 10b3ef2270189fee35ca21b70463481353f1e160 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Mon, 24 Jun 2019 01:30:00 -0700 Subject: [PATCH 154/185] scsi: bnx2fc: Update the driver version to 2.12.10 Update the driver version to 2.12.10. Signed-off-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 170abe90007a..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: " From 177709c0702e7351dae3b9b4f9de3140a9ee3a06 Mon Sep 17 00:00:00 2001 From: Lin Yi Date: Tue, 25 Jun 2019 10:34:16 +0800 Subject: [PATCH 155/185] scsi: bnx2fc: fix bnx2fc_cmd refcount imbalance in send_rec If cb_arg alloc failed, we can't release the struct orig_io_req refcount before we take its refcount. As Saurav said, move the rec_err label down to avoid unnecessary refcount release and nullptr free. Signed-off-by: Lin Yi Acked-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_els.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 8de5b70f6727..9a8e40bc694b 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; } From 7bfe5ae57c803dd529aaf6feb32c3b49ebff66bd Mon Sep 17 00:00:00 2001 From: Lin Yi Date: Tue, 25 Jun 2019 10:35:29 +0800 Subject: [PATCH 156/185] scsi: bnx2fc: fix bnx2fc_cmd refcount imbalance in send_srr If cb_arg alloc failed, we can't release the struct orig_io_req refcount before we take its refcount. As Saurav said, move the srr_err label down to avoid unnecessary refcount release and nullptr free. Signed-off-by: Lin Yi Acked-by: Saurav Kashyap Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_els.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 9a8e40bc694b..754f2e82d955 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -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; } From 4e1c94b047715e12942536d8457e9aa692e8b5fc Mon Sep 17 00:00:00 2001 From: Arthur Simchaev Date: Tue, 25 Jun 2019 15:36:00 +0300 Subject: [PATCH 157/185] scsi: ufs: Documentation: Announce ufs-tool v1.0 The ufs-tool stable release v1.0 is available at: https://github.com/westerndigitalcorporation/ufs-tool Feedback and bug reports, as always, are welcomed. Signed-off-by: Arthur Simchaev Signed-off-by: Martin K. Petersen --- Documentation/scsi/ufs.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt index 1769f71c4c20..81842ec3e116 100644 --- a/Documentation/scsi/ufs.txt +++ b/Documentation/scsi/ufs.txt @@ -158,6 +158,13 @@ send SG_IO with the applicable sg_io_v4: If you wish to read or write a descriptor, use the appropriate xferp of sg_io_v4. +The userspace tool that interacts with the ufs-bsg endpoint and uses its +upiu-based protocol is available at: + + https://github.com/westerndigitalcorporation/ufs-tool + +For more detailed information about the tool and its supported +features, please see the tool's README. UFS Specifications can be found at, UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf From 381abbd1f7f978471722784895d1ff184ef86929 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 24 Jun 2019 10:42:53 -0400 Subject: [PATCH 158/185] scsi: mpt3sas: Remove CPU arch check to determine perf_mode Currently default perf_mode is set to 'balanced' on Intel architecture machines and on other machines default perf_mode is set to 'latency' mode. This CPU architecture check is removed and the default perf_mode mode is set to 'balanced' mode on all machines. User can choose the required performance mode using perf_mode module parameter. Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index cae74418015d..d55f13495b20 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -113,8 +113,7 @@ MODULE_PARM_DESC(perf_mode, "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 - on Intel architecture, default perf_mode is\n\t\t" - " 'balanced' and in others architectures the default mode is 'latency'" + "\t\tdefault - default perf_mode is 'balanced'" ); enum mpt3sas_perf_mode { @@ -2990,19 +2989,6 @@ _base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, if (perf_mode == MPT_PERF_MODE_DEFAULT) { -#if defined(CONFIG_X86) - /* - * Use global variable boot_cpu_data.x86_vendor to - * determine whether the architecture is Intel or not. - */ - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) { - ioc->high_iops_queues = 0; - return; - } -#else - ioc->high_iops_queues = 0; - return; -#endif speed = pcie_get_speed_cap(ioc->pdev); dev_info(&ioc->pdev->dev, "PCIe device speed is %s\n", speed == PCIE_SPEED_2_5GT ? "2.5GHz" : From 48d6f0a6a5595abb38d899dbf8ca09f7dc858d2b Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 24 Jun 2019 10:42:54 -0400 Subject: [PATCH 159/185] scsi: mpt3sas: Use configured PCIe link speed, not max When enabling high iops queues, the driver should use the HBA's configured PCIe link speed instead of looking for the maximum link speed. I.e. enable high iops queues only if Aero/Sea HBA's configured PCIe link speed is set to 16GT/s. Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index d55f13495b20..8a47e0238a11 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2979,7 +2979,7 @@ static void _base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, int hba_msix_vector_count) { - enum pci_bus_speed speed = PCI_SPEED_UNKNOWN; + u16 lnksta, speed; if (perf_mode == MPT_PERF_MODE_IOPS || perf_mode == MPT_PERF_MODE_LATENCY) { @@ -2989,15 +2989,10 @@ _base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, if (perf_mode == MPT_PERF_MODE_DEFAULT) { - speed = pcie_get_speed_cap(ioc->pdev); - dev_info(&ioc->pdev->dev, "PCIe device speed is %s\n", - speed == PCIE_SPEED_2_5GT ? "2.5GHz" : - speed == PCIE_SPEED_5_0GT ? "5.0GHz" : - speed == PCIE_SPEED_8_0GT ? "8.0GHz" : - speed == PCIE_SPEED_16_0GT ? "16.0GHz" : - "Unknown"); + pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta); + speed = lnksta & PCI_EXP_LNKSTA_CLS; - if (speed < PCIE_SPEED_16_0GT) { + if (speed < 0x4) { ioc->high_iops_queues = 0; return; } From 610ef1e955cd262a5f72d8401a36c9cfca6072fe Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 24 Jun 2019 10:42:55 -0400 Subject: [PATCH 160/185] scsi: mpt3sas: Determine smp affinity on per HBA basis Even though 'smp_affinity_enable' module parameter is enabled, if the number of online CPUs is bigger than the number of msix vectors enabled on that HBA, then smp affinity settings should be disabled only for this HBA. But currently the smp affinity setting is disabled globally and hence smp affinity will be disabled for subsequent HBAs even though number of msix vectors enabled for this HBA matches the number of online CPU. To fix this, define a per HBA variable smp_affinity_enable. Initially this variable is initialized with smp_affinity_enable module parameter value. If this HBA has less number of msix vectors configured when compared to number of online cpus, then only this HBA's variable smp_affinity_enable is set to zero. Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 10 ++++++---- drivers/scsi/mpt3sas/mpt3sas_base.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 8a47e0238a11..722599a74352 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2813,7 +2813,7 @@ _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 (smp_affinity_enable) + 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), @@ -2898,7 +2898,7 @@ _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 @@ -3033,7 +3033,7 @@ _base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc) struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues }; struct irq_affinity *descp = &desc; - if (smp_affinity_enable) + if (ioc->smp_affinity_enable) irq_flags |= PCI_IRQ_AFFINITY; else descp = NULL; @@ -3091,7 +3091,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) goto try_ioapic; if (ioc->msix_vector_count < ioc->cpu_count) - smp_affinity_enable = 0; + ioc->smp_affinity_enable = 0; r = _base_alloc_irq_vectors(ioc); if (r < 0) { @@ -6897,6 +6897,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) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 44b8a23d5974..6afbdb044310 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1405,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; From eedc42a074de55a0164e722d5ca2ec4bd397b8bc Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 24 Jun 2019 10:42:56 -0400 Subject: [PATCH 161/185] scsi: mpt3sas: Fix msix load balance on and off settings Enable msix load balance only when combined reply queue mode is disabled on the SAS3 and above generation HBA devices. Earlier msix load balance used to enable if the number of online cpus is greater than the number of MSI-X vectors enabled on the HBA. Combined reply queue mode will be disabled only on those HBA which works in shared resources mode. I.e. on SAS3 HBAs it will be <= 8 and on SAS35 HBA devices it will be <= 16. - Before this patch if system has 256 logical CPUs and HBA exposes 128 MSI-X vectors, driver will enable msix load balance. - After this patch if system has 256 logical CPUs and HBA exposes 128 MSI-X vectors, driver will disable msix load balance. - After this patch if system has 256 logical CPUs and HBA exposes 16 MSI-X vectors (due to combined reply queue mode being off in HW), driver will enable msix load balance. Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 722599a74352..684662888792 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2884,11 +2884,9 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) if (!_base_is_controller_msix_enabled(ioc)) return; - ioc->msix_load_balance = false; - if (ioc->reply_queue_count < num_online_cpus()) { - ioc->msix_load_balance = true; + + if (ioc->msix_load_balance) return; - } memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); @@ -3060,6 +3058,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) int i, local_max_msix_vectors; u8 try_msix = 0; + ioc->msix_load_balance = false; + if (msix_disable == -1 || msix_disable == 0) try_msix = 1; @@ -3090,7 +3090,20 @@ _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) + /* + * 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; + } + + /* + * smp affinity setting is not need when msix load balance + * is enabled. + */ + if (ioc->msix_load_balance) ioc->smp_affinity_enable = 0; r = _base_alloc_irq_vectors(ioc); From 2040a857e436e5e942d3d2d893891d088dba87f1 Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Mon, 24 Jun 2019 13:52:27 +0530 Subject: [PATCH 162/185] scsi: pm80xx: Event log size through sysfs Added support to read event log size from MPI configuration table and export through sysfs. Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Reviewed-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index d193961ea82f..c7e0a42c3d0d 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -461,6 +461,24 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev, return str - buf; } 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 @@ -796,6 +814,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, From 5f0bd875c6dbc6245b4012b13bf6b81cc629cb4c Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Mon, 24 Jun 2019 13:52:28 +0530 Subject: [PATCH 163/185] scsi: pm80xx: Modified the logic to collect IOP event logs Added the logic for collecting IOP log respective to event log size. Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Reviewed-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index c7e0a42c3d0d..6b85016b4db3 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -492,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); From 5885571df750d0ed3f8996e161cdcc56f4a94bfe Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:19 +0530 Subject: [PATCH 164/185] scsi: megaraid_sas: Add 32 bit atomic descriptor support to AERO adapters Aero adapters provides Atomic Request Descriptor as an alternative method for posting an entry onto a request queue. The posting of an Atomic Request Descriptor is an atomic operation, providing a safe mechanism for multiple processors on the host to post requests without synchronization. This Atomic Request Descriptor format is identical to first 32 bits of Default Request Descriptor and uses only 32 bits. If Aero adapters support Atomic descriptor, driver should use it for posting IOs and DCMDs to firmware. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 3 ++ drivers/scsi/megaraid/megaraid_sas_fusion.c | 45 ++++++++++++++++----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index e138d1447e43..a08dd9c52a25 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1600,6 +1600,8 @@ 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 MEGASAS_WATCHDOG_THREAD_INTERVAL 1000 @@ -2395,6 +2397,7 @@ struct megasas_instance { struct dentry *raidmap_dump; #endif u8 enable_fw_dev_list; + bool atomic_desc_support; }; struct MR_LD_VF_MAP { u32 size; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 8a7ac5c09c53..44114087d50e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -277,21 +277,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; @@ -304,6 +300,25 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, #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 @@ -1171,7 +1186,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); @@ -1181,6 +1197,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: From dd80769923ded673db82df5a557b4cce9c5358e7 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:20 +0530 Subject: [PATCH 165/185] scsi: megaraid_sas: Add support for Non-secure Aero PCI IDs This patch will add support for non-secure Aero adapter PCI IDs. Driver will throw an error message when a non-secure type controller is detected. Purpose of this interface is to avoid interacting with any firmware which is not secured/signed by Broadcom. Any tampering on Firmware component will be detected by hardware and it will be communicated to the driver to avoid any further interaction with that component. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 4 ++++ drivers/scsi/megaraid/megaraid_sas_base.c | 25 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index a08dd9c52a25..61bcf7a4867f 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -64,6 +64,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 diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 54908981b382..7d1cf4eca22d 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -168,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)}, {} }; @@ -6991,6 +6995,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"); @@ -7246,6 +7256,10 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) struct megasas_instance *instance; instance = pci_get_drvdata(pdev); + + if (!instance) + return 0; + instance->unload = 1; dev_info(&pdev->dev, "%s is called\n", __func__); @@ -7299,6 +7313,10 @@ 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); @@ -7467,6 +7485,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; @@ -7595,6 +7617,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)) From 2181aacf46f35cfa1c2ad24f15a4eb1be860e324 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:21 +0530 Subject: [PATCH 166/185] scsi: megaraid_sas: Remove few debug counters from IO path Signed-off-by: Kashyap Desai Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 5 ----- drivers/scsi/megaraid/megaraid_sas_fusion.c | 5 ----- 2 files changed, 10 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 61bcf7a4867f..a9720216cad0 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2323,11 +2323,6 @@ struct megasas_instance { 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; struct megasas_instance_template *instancet; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 44114087d50e..dac855234c6c 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2066,7 +2066,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; } } @@ -2076,7 +2075,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; } } @@ -2085,7 +2083,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; } } @@ -2218,7 +2215,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; } @@ -2293,7 +2289,6 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, memset(sgl_ptr, 0, instance->max_chain_frame_sz); } } - atomic_inc(&instance->ieee_sgl); } /** From a6ffd5bf681905729a4926cb3006d0329dd5d857 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:22 +0530 Subject: [PATCH 167/185] scsi: megaraid_sas: Call disable_irq from process IRQ poll On PowerPC architecture, calling disable_irq_nosync from IRQ context is not providing the required effect. In current megaraid_sas driver, disable_irq_nosync is being called from IRQ context before enabling IRQ poll. But due to the issue seen on PPC, after IRQ poll disable and legacy ISR is enabled, we are not seeing our ISR getting called. Fix: Call disable_irq from IRQ poll thread context instead of IRQ context. Signed-off-by: Shivasharan S Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_fusion.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index a9720216cad0..d333b8e302f9 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2186,6 +2186,7 @@ struct megasas_irq_context { u32 os_irq; struct irq_poll irqpoll; bool irq_poll_scheduled; + bool irq_line_enable; }; struct MR_DRV_SYSTEM_INFO { diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index dac855234c6c..b8a5bbf45850 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3601,7 +3601,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, if (irq_context) { if (!irq_context->irq_poll_scheduled) { irq_context->irq_poll_scheduled = true; - disable_irq_nosync(irq_context->os_irq); + irq_context->irq_line_enable = true; irq_poll_sched(&irq_context->irqpoll); } return num_completed; @@ -3681,6 +3681,11 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget) 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); @@ -3726,6 +3731,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) From 7fa3174b3ef4e517ebb8a08078871ceab705a969 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:23 +0530 Subject: [PATCH 168/185] scsi: megaraid_sas: Release Mutex lock before OCR in case of DCMD timeout Issue: There is possibility of few DCMDs timing out with 'reset_mutex' lock held. As part of DCMD timeout handling, driver calls function megasas_reset_fusion which also tries to acquire same lock 'reset_mutex' and end up with deadlock. Fix: Upon timeout of DCMDs (which are fired with 'reset_mutex' lock held), driver will release 'reset_mutex' before calling OCR function and will acquire lock again after OCR function returns. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 7d1cf4eca22d..54bb48ebfc38 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4369,8 +4369,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); @@ -4861,8 +4863,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); @@ -5010,8 +5014,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); @@ -5141,8 +5147,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); @@ -6398,8 +6406,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); @@ -7801,10 +7811,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) { From ccf6c1f2e2d737e23124691b9a8eeb1b3fc74458 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:24 +0530 Subject: [PATCH 169/185] scsi: megaraid_sas: In probe context, retry IOC INIT once if firmware is in fault Issue: Under certain conditions, controller goes in FAULT state after IOC INIT fired to firmware. Such Fault can be recovered through controller reset. Fix: In driver probe context, if firmware fault is observed post IOC INIT, driver would do controller reset followed by retry logic for IOC INIT command. Signed-off-by: Shivasharan S Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 25 +++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index b8a5bbf45850..2e711b10ccc2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1009,6 +1009,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; @@ -1018,6 +1019,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) @@ -1720,6 +1727,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; @@ -1802,8 +1810,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)) { From 798d44b04f48237b3415c1066fd8f4d8b8fbb53b Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:25 +0530 Subject: [PATCH 170/185] scsi: megaraid_sas: Don't send FPIO to RL Bypass queue Firmware does not expect FastPath IO sent through Region Lock Bypass queue. Though firmware never exposes such settings when fastpath IO can be sent to RL bypass queue but it's safer to remove dead code which directs fastpath IO to RL Bypass queue. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 2e711b10ccc2..a765662f7932 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2876,10 +2876,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); From 59db5a931bbe73f4d03dadb7365d0da2d425e769 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:26 +0530 Subject: [PATCH 171/185] scsi: megaraid_sas: Handle sequence JBOD map failure at driver level Issue: This issue is applicable to scenario when JBOD sequence map is unavailable (memory allocation for JBOD sequence map failed) to driver but feature is supported by firmware. If the driver sends a JBOD IO by not adding 255 (MAX_PHYSICAL_DEVICES - 1) to device ID when underlying firmware supports JBOD sequence map, it will lead to the IO failure. Fix: For JBOD IOs, driver will not use the RAID map to fetch the devhandle if JBOD sequence map is unavailable. Driver will set Devhandle to 0xffff and Target ID to 'device ID + 255 (MAX_PHYSICAL_DEVICES - 1)'. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 2 + drivers/scsi/megaraid/megaraid_sas_base.c | 14 ++-- drivers/scsi/megaraid/megaraid_sas_fusion.c | 77 ++++++++++++--------- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index d333b8e302f9..cd632814e47a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2398,7 +2398,9 @@ struct megasas_instance { #endif u8 enable_fw_dev_list; bool atomic_desc_support; + bool support_seqnum_jbod_fp; }; + struct MR_LD_VF_MAP { u32 size; union MR_LD_REF ref; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 54bb48ebfc38..554ec72811e7 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5103,7 +5103,7 @@ 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; @@ -5140,6 +5140,8 @@ 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"); break; @@ -5554,10 +5556,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; @@ -6042,8 +6046,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; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index a765662f7932..5121d4c6eea3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3083,44 +3083,55 @@ 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; From a4413a5859f8a36e9217e808d172e9458ece4ff0 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:27 +0530 Subject: [PATCH 172/185] scsi: megaraid_sas: megaraid_sas: Add check for count returned by HOST_DEVICE_LIST DCMD Signed-off-by: Shivasharan S Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 554ec72811e7..a886de3e3ffb 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -4827,6 +4827,9 @@ 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); From 49f2bf1071f06a430920888ff2d1a89395a3b6b5 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:28 +0530 Subject: [PATCH 173/185] scsi: megaraid_sas: RAID1 PCI bandwidth limit algorithm is applicable for only Ventura RAID1 PCI bandwidth limit algorithm is not applicable to Aero as it's PCIe Gen4 adapter. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +++ drivers/scsi/megaraid/megaraid_sas_fusion.c | 24 +++++++++++---------- drivers/scsi/megaraid/megaraid_sas_fusion.h | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index a886de3e3ffb..5244b6eedfec 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5777,6 +5777,9 @@ static int megasas_init_fw(struct megasas_instance *instance) MR_MAX_RAID_MAP_SIZE_MASK); } + if (instance->adapter_type == VENTURA_SERIES) + fusion->pcie_bw_limitation = true; + /* Check if MSI-X is supported while in ready state */ msix_enable = (instance->instancet->read_fw_status_reg(instance) & 0x4000000) >> 0x1a; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 5121d4c6eea3..ad18474f06b7 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2621,9 +2621,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; @@ -2681,11 +2682,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); } } @@ -2834,8 +2835,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) @@ -2860,7 +2862,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 diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 98738290c533..b50da3822aa0 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -1335,7 +1335,7 @@ 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; }; union desc_value { From 7fc557005c454fa053153ac0bf7c7c96f58dab4f Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:29 +0530 Subject: [PATCH 174/185] scsi: megaraid_sas: Offload Aero RAID5/6 division calculations to driver For RAID5/RAID6 volumes configured behind Aero, driver will be doing 64bit division operations on behalf of firmware as controller's ARM CPU is very slow in this division. Later, driver calculates Q-ARM, P-ARM and Log-ARM and passes those values to firmware by writing these values to RAID_CONTEXT. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 10 ++- drivers/scsi/megaraid/megaraid_sas_fp.c | 78 +++++++++++++++++++++ drivers/scsi/megaraid/megaraid_sas_fusion.c | 6 +- drivers/scsi/megaraid/megaraid_sas_fusion.h | 24 +++++-- 4 files changed, 108 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 5244b6eedfec..81e708b2eca0 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5777,8 +5777,16 @@ static int megasas_init_fw(struct megasas_instance *instance) MR_MAX_RAID_MAP_SIZE_MASK); } - if (instance->adapter_type == VENTURA_SERIES) + 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) & diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index d296255a4f12..43a2e49807c4 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -901,6 +901,77 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, return retval; } +/* + * 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; +} + /* ****************************************************************************** * @@ -1108,6 +1179,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 ad18474f06b7..058d22b4fa7b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3324,9 +3324,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 = @@ -3444,7 +3444,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; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index b50da3822aa0..ca32b2b72515 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -87,7 +87,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 }; /* @@ -151,12 +152,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], @@ -247,6 +251,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 @@ -1336,6 +1347,7 @@ struct fusion_context { 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 { From 58136856167d10adc2a190aff88d13b33eafb9e2 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:30 +0530 Subject: [PATCH 175/185] scsi: megaraid_sas: Add support for MPI toolbox commands Added driver support to allow passthrough MPI toolbox type MFI commands to firmware based on firmware capability. Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 36 ++++++++++++++++++++- drivers/scsi/megaraid/megaraid_sas_base.c | 31 +++++++++++++++++- drivers/scsi/megaraid/megaraid_sas_fusion.c | 7 ++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index cd632814e47a..83baac3b8a8e 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -208,6 +208,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 }; @@ -1467,7 +1468,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]; @@ -2399,6 +2432,7 @@ struct megasas_instance { u8 enable_fw_dev_list; bool atomic_desc_support; bool support_seqnum_jbod_fp; + bool support_pci_lane_margining; }; struct MR_LD_VF_MAP { diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 81e708b2eca0..4c7a0930b1a1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -188,6 +188,7 @@ 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; @@ -3494,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; @@ -5099,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. @@ -5112,6 +5115,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance) 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; @@ -5145,6 +5150,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance) 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; @@ -7793,7 +7800,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); @@ -8277,6 +8286,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"); @@ -8546,6 +8563,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)); @@ -8602,8 +8620,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); @@ -8643,6 +8670,8 @@ 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(); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 058d22b4fa7b..e12434130231 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -4245,6 +4245,13 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) result = COMPLETE_CMD; } + 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; From 132147d7f620eed4a7bee815eba03561258fc21e Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:31 +0530 Subject: [PATCH 176/185] scsi: megaraid_sas: Add support for High IOPS queues Aero controllers support balanced performance mode through the ability to configure queues with different properties. Reply queues with interrupt coalescing enabled are called "high iops reply queues" and reply queues with interrupt coalescing disabled are called "low latency reply queues". The driver configures a combination of high iops and low latency reply queues if: - HBA is an AERO controller; - MSI-X vectors supported by the HBA is 128; - Total CPU count in the system more than high iops queue count; - Driver is loaded with default max_msix_vectors module parameter; and - System booted in non-kdump mode. Signed-off-by: Kashyap Desai Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 6 + drivers/scsi/megaraid/megaraid_sas_base.c | 135 +++++++++++++++++--- drivers/scsi/megaraid/megaraid_sas_fusion.c | 11 ++ 3 files changed, 135 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 83baac3b8a8e..5b17d0fa162b 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1640,6 +1640,7 @@ enum FW_BOOT_CONTEXT { #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 @@ -2250,6 +2251,9 @@ 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 + struct megasas_instance { unsigned int *reply_map; @@ -2433,6 +2437,8 @@ struct megasas_instance { bool atomic_desc_support; bool support_seqnum_jbod_fp; bool support_pci_lane_margining; + u8 low_latency_index_start; + bool balanced_mode; }; struct MR_LD_VF_MAP { diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 4c7a0930b1a1..0abef940b67b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5472,6 +5472,8 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance) __func__, __LINE__); return -1; } + instance->balanced_mode = false; + instance->low_latency_index_start = 0; return 0; } @@ -5610,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; @@ -5623,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++; + } } /** @@ -5661,6 +5671,66 @@ int megasas_get_device_list(struct megasas_instance *instance) return SUCCESS; } + +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->balanced_mode && (i != instance->msix_vectors)) { + if (instance->msix_vectors) + pci_free_irq_vectors(instance->pdev); + /* Disable Balanced IOPS mode and try realloc vectors */ + instance->balanced_mode = false; + 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; + +} + /** * megasas_init_fw - Initializes the FW * @instance: Adapter soft state @@ -5680,6 +5750,8 @@ static int megasas_init_fw(struct megasas_instance *instance) int i, j, loop; struct IOV_111 *iovPtr; struct fusion_context *fusion; + bool intr_coalescing; + unsigned int num_msix_req; fusion = instance->ctrl_context; @@ -5799,7 +5871,6 @@ static int megasas_init_fw(struct megasas_instance *instance) 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); @@ -5865,19 +5936,49 @@ static int megasas_init_fw(struct megasas_instance *instance) } 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 (instance->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; - } else { - instance->msix_vectors = 0; + + /* + * 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->balanced_mode = true; + else + instance->balanced_mode = false; + + if (instance->balanced_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. diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index e12434130231..44bfbe8d2ce5 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1058,6 +1058,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; @@ -1091,6 +1092,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->balanced_mode = true; + + dev_info(&instance->pdev->dev, "Balanced mode :%s\n", + instance->balanced_mode ? "Yes" : "No"); + 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", From ea836f40f8fdb47c7dda2e4aaaa28ae676c3fa41 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:32 +0530 Subject: [PATCH 177/185] scsi: megaraid_sas: Enable coalescing for high IOPS queues Driver should enable interrupt coalescing (during driver load and after Controller Reset) for High IOPS queues by masking appropriate bits in IOC INIT frame. Signed-off-by: Kashyap Desai Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 2 +- drivers/scsi/megaraid/megaraid_sas_fusion.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 5b17d0fa162b..02e6e15d8c2a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1819,7 +1819,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 */ diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 44bfbe8d2ce5..845ca2f94e5c 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1186,6 +1186,14 @@ 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) + */ + if (instance->balanced_mode) + init_frame->replyqueue_mask = + cpu_to_le16(~(~0 << instance->low_latency_index_start / 8)); + 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 = From f0b9e7bdc309e8cc63a640009715626376e047c6 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:33 +0530 Subject: [PATCH 178/185] scsi: megaraid_sas: Set affinity for high IOPS reply queues High iops queues are mapped to non-managed IRQs. Set affinity of non-managed irqs to local numa node. Low latency queues are mapped to managed IRQs. Driver reserves some reply queues for high IOPS queues (through pci_alloc_irq_vectors_affinity and .pre_vectors interface). The rest of queues are for low latency. Based on IO workload, driver will decide which group of reply queues (either high IOPS queues or low latency queues) to be used. High IOPS queues will be mapped to local numa node of controller and low latency queues will be mapped to CPUs across numa nodes. In general, high IOPS and low latency queues should fit into 128 reply queues which is the max number of reply queues supported by Aero adapters. Signed-off-by: Kashyap Desai Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 0abef940b67b..33c57e773920 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5672,6 +5672,26 @@ 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->balanced_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) { @@ -5729,6 +5749,8 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance) else instance->msix_vectors = 0; + if (instance->smp_affinity_enable) + megasas_set_high_iops_queue_affinity_hint(instance); } /** From f39e5e52c5b5407173d87b03a6385fbe6ccf1026 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:34 +0530 Subject: [PATCH 179/185] scsi: megaraid_sas: Use high IOPS queues based on IO workload The driver will use round-robin method for IO submission in batches within the high IOPS queues when the number of in-flight ios on the target device is larger than 8. Otherwise the driver will use low latency reply queues. Signed-off-by: Kashyap Desai Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 3 +++ drivers/scsi/megaraid/megaraid_sas_fp.c | 1 + drivers/scsi/megaraid/megaraid_sas_fusion.c | 16 ++++++++++++++-- drivers/scsi/megaraid/megaraid_sas_fusion.h | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 02e6e15d8c2a..3f4cb52177f6 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2253,6 +2253,8 @@ enum MR_PD_TYPE { /*Aero performance parameters*/ #define MR_HIGH_IOPS_QUEUE_COUNT 8 +#define MR_DEVICE_HIGH_IOPS_DEPTH 8 +#define MR_HIGH_IOPS_BATCH_COUNT 16 struct megasas_instance { @@ -2362,6 +2364,7 @@ struct megasas_instance { atomic_t ldio_outstanding; atomic_t fw_reset_no_pci_access; atomic64_t total_io_count; + atomic64_t high_iops_outstanding; struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 43a2e49807c4..f9f7c34e93c3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -1038,6 +1038,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 diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 845ca2f94e5c..90dced4290a2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2811,6 +2811,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; @@ -2830,7 +2831,13 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, fp_possible = (io_info.fpOkForIo > 0) ? true : false; } - if (instance->msix_load_balance) + if (instance->balanced_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)); @@ -3157,7 +3164,12 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; - if (instance->msix_load_balance) + if (instance->balanced_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)); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index ca32b2b72515..6fe334348c46 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -962,6 +962,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 { From 299ee42615e3f5f10dc8604b995368bd05c6a687 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:35 +0530 Subject: [PATCH 180/185] scsi: megaraid_sas: Introduce various Aero performance modes For Aero adapters, driver provides three different performance modes controlled through module parameter named 'perf_mode'. Below are those performance modes: 0: Balanced - Additional high IOPS reply queues will be enabled along with low latency queues. Interrupt coalescing will be enabled only for these high IOPS reply queues. 1: IOPS - No additional high IOPS queues are enabled. Interrupt coalescing will be enabled on all reply queues. 2: Latency - No additional high IOPS queues are enabled. Interrupt coalescing will be disabled on all reply queues. This is a legacy behavior similar to Ventura & Invader Series. Default performance mode settings: - Performance mode set to 'Balanced', if Aero controller is working in 16GT/s PCIe speed. - Performance mode will be set to 'Latency' mode for all other cases. Through module parameter 'perf_mode', user can override default performance mode to desired one. Captured some performance numbers with these performance modes. 4k Random Read IO performance numbers on 24 SAS SSD drives for above three performance modes. Performance data is from Intel Skylake and HGST SS300 (drive model SDLL1DLR400GCCA1). IOPS: ----------------------------------------------------------------------- |perf_mode | qd = 1 | qd = 64 | note | |-------------|--------|---------|------------------------------------- |balanced | 259K | 3061k | Provides max performance numbers | | | | | both on lower QD workload & | | | | | also on higher QD workload | |-------------|--------|---------|------------------------------------- |iops | 220K | 3100k | Provides max performance numbers | | | | | only on higher QD workload. | |-------------|--------|---------|------------------------------------- |latency | 246k | 2226k | Provides good performance numbers | | | | | only on lower QD worklaod. | ----------------------------------------------------------------------- Average Latency: ----------------------------------------------------- |perf_mode | qd = 1 | qd = 64 | |-------------|--------------|----------------------| |balanced | 92.05 usec | 501.12 usec | |-------------|--------------|----------------------| |iops | 108.40 usec | 498.10 usec | |-------------|--------------|----------------------| |latency | 97.10 usec | 689.26 usec | ----------------------------------------------------- Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 14 ++++- drivers/scsi/megaraid/megaraid_sas_base.c | 60 ++++++++++++++++++--- drivers/scsi/megaraid/megaraid_sas_fusion.c | 22 +++++--- 3 files changed, 81 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3f4cb52177f6..03e786981563 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2256,6 +2256,18 @@ enum MR_PD_TYPE { #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; @@ -2441,7 +2453,7 @@ struct megasas_instance { bool support_seqnum_jbod_fp; bool support_pci_lane_margining; u8 low_latency_index_start; - bool balanced_mode; + int perf_mode; }; struct MR_LD_VF_MAP { diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 33c57e773920..bd6da59c087f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -105,6 +105,18 @@ unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; 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"); @@ -5472,7 +5484,7 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance) __func__, __LINE__); return -1; } - instance->balanced_mode = false; + instance->perf_mode = MR_LATENCY_PERF_MODE; instance->low_latency_index_start = 0; return 0; } @@ -5683,7 +5695,7 @@ megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance) int i; int local_numa_node; - if (instance->balanced_mode) { + 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++) @@ -5726,11 +5738,12 @@ megasas_alloc_irq_vectors(struct megasas_instance *instance) i = __megasas_alloc_irq_vectors(instance); - if (instance->balanced_mode && (i != instance->msix_vectors)) { + 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->balanced_mode = false; + instance->perf_mode = MR_LATENCY_PERF_MODE; instance->low_latency_index_start = 1; num_msix_req = num_online_cpus() + instance->low_latency_index_start; @@ -5774,6 +5787,7 @@ static int megasas_init_fw(struct megasas_instance *instance) struct fusion_context *fusion; bool intr_coalescing; unsigned int num_msix_req; + u16 lnksta, speed; fusion = instance->ctrl_context; @@ -5983,11 +5997,43 @@ static int megasas_init_fw(struct megasas_instance *instance) if (intr_coalescing && (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) && (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES)) - instance->balanced_mode = true; + instance->perf_mode = MR_BALANCED_PERF_MODE; else - instance->balanced_mode = false; + instance->perf_mode = MR_LATENCY_PERF_MODE; - if (instance->balanced_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 diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 90dced4290a2..8a3e2551a6e1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -1097,10 +1097,10 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) if ((instance->low_latency_index_start == MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing) - instance->balanced_mode = true; + instance->perf_mode = MR_BALANCED_PERF_MODE; - dev_info(&instance->pdev->dev, "Balanced mode :%s\n", - instance->balanced_mode ? "Yes" : "No"); + 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; @@ -1190,9 +1190,17 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) * Each bit in replyqueue_mask represents one group of MSI-x vectors * (each group has 8 vectors) */ - if (instance->balanced_mode) + switch (instance->perf_mode) { + case MR_BALANCED_PERF_MODE: init_frame->replyqueue_mask = - cpu_to_le16(~(~0 << instance->low_latency_index_start / 8)); + 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)); @@ -2831,7 +2839,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, fp_possible = (io_info.fpOkForIo > 0) ? true : false; } - if (instance->balanced_mode && + 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 = @@ -3164,7 +3172,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; - if (instance->balanced_mode && + 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) / From f5258d6e01f3c707d9ba70b2a14a158a6fadef11 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Tue, 25 Jun 2019 16:34:36 +0530 Subject: [PATCH 181/185] scsi: megaraid_sas: Update driver version to 07.710.06.00-rc1 Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 03e786981563..11565597c6d5 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -33,8 +33,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "07.708.03.00-rc1" -#define MEGASAS_RELDATE "March 14, 2019" +#define MEGASAS_VERSION "07.710.06.00-rc1" +#define MEGASAS_RELDATE "June 18, 2019" /* * Device IDs From 6a81533d616fe581b0d421ee6db3319eeac9486d Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Fri, 21 Jun 2019 09:50:22 -0700 Subject: [PATCH 182/185] scsi: qla2xxx: Fix kernel crash after disconnecting NVMe devices BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] qla_nvme_unregister_remote_port+0x6c/0xf0 [qla2xxx] PGD 800000084cf41067 PUD 84d288067 PMD 0 Oops: 0000 [#1] SMP Call Trace: [] process_one_work+0x17f/0x440 [] worker_thread+0x126/0x3c0 [] ? manage_workers.isra.26+0x2a0/0x2a0 [] kthread+0xd1/0xe0 [] ? insert_kthread_work+0x40/0x40 [] ret_from_fork_nospec_begin+0x21/0x21 [] ? insert_kthread_work+0x40/0x40 RIP [] qla_nvme_unregister_remote_port+0x6c/0xf0 [qla2xxx] The crash is due to a bad entry in the nvme_rport_list. This list is not protected, and when a remoteport_delete callback is called, driver traverses the list and crashes. Actually, the list could be removed and driver could traverse the main fcport list instead. Fix does exactly that. Signed-off-by: Arun Easi Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 - drivers/scsi/qla2xxx/qla_nvme.c | 37 +++++++++------------------------ drivers/scsi/qla2xxx/qla_nvme.h | 1 - drivers/scsi/qla2xxx/qla_os.c | 1 - 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1a4095c56eee..602ed24bb806 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4376,7 +4376,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; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 22e3fba28e51..b43c62758cec 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -74,7 +74,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; @@ -542,19 +541,12 @@ 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)) { @@ -590,7 +582,7 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) { struct fc_port *fcport = container_of(work, struct fc_port, nvme_del_work); - struct qla_nvme_rport *qla_rport, *trport; + int ret; if (!IS_ENABLED(CONFIG_NVME_FC)) return; @@ -598,23 +590,14 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) ql_log(ql_log_warn, NULL, 0x2112, "%s: unregister remoteport on %p\n",__func__, fcport); - list_for_each_entry_safe(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); - nvme_fc_set_remoteport_devloss - (fcport->nvme_remote_port, 0); - init_completion(&fcport->nvme_del_done); - if (nvme_fc_unregister_remoteport - (fcport->nvme_remote_port)) - ql_log(ql_log_info, fcport->vha, 0x2114, - "%s: Failed to unregister nvme_remote_port\n", - __func__); - wait_for_completion(&fcport->nvme_del_done); - break; - } - } + 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 d3b8a6440113..2d088add7011 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.h +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -37,7 +37,6 @@ struct nvme_private { }; struct qla_nvme_rport { - struct list_head list; struct fc_port *fcport; }; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index e1c82a0a9745..1a014d633d5f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4789,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); From 2eb9238affa72a5260b14388cf56598f7413109b Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 21 Jun 2019 09:50:23 -0700 Subject: [PATCH 183/185] scsi: qla2xxx: on session delete, return nvme cmd - on session delete or chip reset, reject all NVME commands. - on NVME command submission error, free srb resource. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index b43c62758cec..8b3cb0fd307e 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -239,8 +239,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) @@ -272,6 +280,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, "qla2x00_start_sp failed = %d\n", rval); atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); + sp->free(sp); return rval; } @@ -486,11 +495,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 @@ -523,6 +532,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, "qla2x00_start_nvme_mq failed = %d\n", rval); atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); + sp->free(sp); } return rval; @@ -549,14 +559,13 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) 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); - } + 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); } static struct nvme_fc_port_template qla_nvme_fc_transport = { @@ -588,7 +597,8 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) return; ql_log(ql_log_warn, NULL, 0x2112, - "%s: unregister remoteport on %p\n",__func__, fcport); + "%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); From 4c2a2d0178d5d8006a6bc50c8dc0ed122e4e946e Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 21 Jun 2019 09:50:24 -0700 Subject: [PATCH 184/185] scsi: qla2xxx: Fix NVME cmd and LS cmd timeout race condition This patch uses kref to protect access between fcp_abort path and nvme command and LS command completion path. Stack trace below shows the abort path is accessing stale memory (nvme_private->sp). When command kref reaches 0, nvme_private & srb resource will be disconnected from each other. Any subsequence nvme abort request will not be able to reference the original srb. [ 5631.003998] BUG: unable to handle kernel paging request at 00000010000005d8 [ 5631.004016] IP: [] qla_nvme_abort_work+0x22/0x100 [qla2xxx] [ 5631.004086] Workqueue: events qla_nvme_abort_work [qla2xxx] [ 5631.004097] RIP: 0010:[] [] qla_nvme_abort_work+0x22/0x100 [qla2xxx] [ 5631.004109] Call Trace: [ 5631.004115] [] ? pwq_dec_nr_in_flight+0x64/0xb0 [ 5631.004117] [] process_one_work+0x17f/0x440 [ 5631.004120] [] worker_thread+0x126/0x3c0 Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 3 + drivers/scsi/qla2xxx/qla_nvme.c | 171 ++++++++++++++++++++++---------- drivers/scsi/qla2xxx/qla_nvme.h | 1 + 3 files changed, 121 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 602ed24bb806..c0d1b0715541 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -532,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; @@ -554,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) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 8b3cb0fd307e..316aea085e6e 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -123,53 +123,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_iocb *nvme; - struct nvmefc_ls_req *fd; - struct nvme_private *priv; - - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - - atomic_dec(&sp->ref_count); - - if (res) - res = -EINVAL; - - nvme = &sp->u.iocb_cmd; - fd = nvme->u.nvme.desc; - priv = fd->private; - priv->comp_status = res; - schedule_work(&priv->ls_work); - /* work schedule doesn't need the sp */ - qla2x00_rel_sp(sp); -} - -static void qla_nvme_sp_done(void *ptr, int res) -{ - srb_t *sp = ptr; - struct srb_iocb *nvme; + 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; + unsigned long flags; + + if (!priv) + goto out; nvme = &sp->u.iocb_cmd; fd = nvme->u.nvme.desc; - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - - atomic_dec(&sp->ref_count); - - if (res == QLA_SUCCESS) { + 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); +} + +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; + + priv = (struct nvme_private *)sp->priv; + priv->comp_status = res; + INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); + schedule_work(&priv->ls_work); +} + +/* it assumed that QPair lock is held. */ +static void qla_nvme_sp_done(void *ptr, int res) +{ + srb_t *sp = ptr; + struct nvme_private *priv = (struct nvme_private *)sp->priv; + + priv->comp_status = res; + kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref); return; } @@ -188,44 +226,50 @@ static void qla_nvme_abort_work(struct work_struct *work) __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); - return; + goto out; } - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - rval = ha->isp_ops->abort_command(sp); ql_dbg(ql_dbg_io, fcport->vha, 0x212b, "%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) @@ -257,11 +301,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; @@ -278,9 +324,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->free(sp); + sp->priv = NULL; + priv->sp = NULL; + qla2x00_rel_sp(sp); return rval; } @@ -292,6 +339,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); @@ -515,12 +574,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; @@ -530,9 +592,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->free(sp); + sp->priv = NULL; + priv->sp = NULL; + qla2xxx_rel_qpair_sp(sp->qpair, sp); } return rval; diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h index 2d088add7011..67bb4a2a3742 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.h +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -34,6 +34,7 @@ struct nvme_private { struct work_struct ls_work; struct work_struct abort_work; int comp_status; + spinlock_t cmd_lock; }; struct qla_nvme_rport { From baf23eddbf2a4ba9bf2bdb342686c71a8042e39b Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Sun, 16 Jun 2019 08:05:53 -0700 Subject: [PATCH 185/185] scsi: qla2xxx: move IO flush to the front of NVME rport unregistration On session deletion, current qla code would unregister an NVMe session before flushing IOs. This patch would move the unregistration of NVMe session after IO flush. This way FC-NVMe layer would not have to wait for stuck IOs. In addition, qla2xxx would stop accepting new IOs during session deletion. Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 - drivers/scsi/qla2xxx/qla_gbl.h | 2 ++ drivers/scsi/qla2xxx/qla_nvme.c | 14 ++------------ drivers/scsi/qla2xxx/qla_target.c | 16 ++++++++-------- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c0d1b0715541..bad2b12604f1 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2339,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 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index bbe69ab5cf3f..f9669fdf7798 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -908,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_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 316aea085e6e..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)); @@ -619,16 +616,11 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) fcport = qla_rport->fcport; fcport->nvme_remote_port = NULL; fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; - - complete(&fcport->nvme_del_done); - - 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 %8phN completed.\n", fcport, fcport->port_name); + complete(&fcport->nvme_del_done); } static struct nvme_fc_port_template qla_nvme_fc_transport = { @@ -650,10 +642,8 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .fcprqst_priv_sz = sizeof(struct nvme_private), }; -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); int ret; if (!IS_ENABLED(CONFIG_NVME_FC)) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 3eeae72793bc..b9ee0fa37c27 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1013,6 +1013,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); } } @@ -1164,14 +1170,8 @@ void qlt_unreg_sess(struct fc_port *sess) sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; - if (sess->nvme_flag & NVME_FLAG_REGISTERED && - !(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);