linux/drivers/ata/sata_nv.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  sata_nv.c - NVIDIA nForce SATA
 *
 *  Copyright 2004 NVIDIA Corp.  All rights reserved.
 *  Copyright 2004 Andrew Chew
 *
 *  libata documentation is available via 'make {ps|pdf}docs',
 *  as Documentation/driver-api/libata.rst
 *
 *  No hardware documentation available outside of NVIDIA.
 *  This driver programs the NVIDIA SATA controller in a similar
 *  fashion as with other PCI IDE BMDMA controllers, with a few
 *  NV-specific details such as register offsets, SATA phy location,
 *  hotplug info, etc.
 *
 *  CK804/MCP04 controllers support an alternate programming interface
 *  similar to the ADMA specification (with some modifications).
 *  This allows the use of NCQ. Non-DMA-mapped ATA commands are still
 *  sent through the legacy interface.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <linux/libata.h>
#include <trace/events/libata.h>

#define DRV_NAME
#define DRV_VERSION

#define NV_ADMA_DMA_BOUNDARY

enum {};

/* ADMA Physical Region Descriptor - one SG segment */
struct nv_adma_prd {};

enum nv_adma_regbits {};

/* ADMA Command Parameter Block
   The first 5 SG segments are stored inside the Command Parameter Block itself.
   If there are more than 5 segments the remainder are stored in a separate
   memory area indicated by next_aprd. */
struct nv_adma_cpb {};


struct nv_adma_port_priv {};

struct nv_host_priv {};

struct defer_queue {};

enum ncq_saw_flag_list {};

struct nv_swncq_port_priv {};


#define NV_ADMA_CHECK_INTR(GCTL, PORT)

static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM_SLEEP
static int nv_pci_device_resume(struct pci_dev *pdev);
#endif
static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);

static int nv_hardreset(struct ata_link *link, unsigned int *class,
			unsigned long deadline);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
static void nv_ck804_freeze(struct ata_port *ap);
static void nv_ck804_thaw(struct ata_port *ap);
static int nv_adma_device_configure(struct scsi_device *sdev,
		struct queue_limits *lim);
static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
static enum ata_completion_errors nv_adma_qc_prep(struct ata_queued_cmd *qc);
static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc);
static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
static void nv_adma_irq_clear(struct ata_port *ap);
static int nv_adma_port_start(struct ata_port *ap);
static void nv_adma_port_stop(struct ata_port *ap);
#ifdef CONFIG_PM
static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int nv_adma_port_resume(struct ata_port *ap);
#endif
static void nv_adma_freeze(struct ata_port *ap);
static void nv_adma_thaw(struct ata_port *ap);
static void nv_adma_error_handler(struct ata_port *ap);
static void nv_adma_host_stop(struct ata_host *host);
static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);

static void nv_mcp55_thaw(struct ata_port *ap);
static void nv_mcp55_freeze(struct ata_port *ap);
static void nv_swncq_error_handler(struct ata_port *ap);
static int nv_swncq_device_configure(struct scsi_device *sdev,
		struct queue_limits *lim);
static int nv_swncq_port_start(struct ata_port *ap);
static enum ata_completion_errors nv_swncq_qc_prep(struct ata_queued_cmd *qc);
static void nv_swncq_fill_sg(struct ata_queued_cmd *qc);
static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc);
static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis);
static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance);
#ifdef CONFIG_PM
static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int nv_swncq_port_resume(struct ata_port *ap);
#endif

enum nv_host_type
{};

static const struct pci_device_id nv_pci_tbl[] =;

static struct pci_driver nv_pci_driver =;

static const struct scsi_host_template nv_sht =;

static const struct scsi_host_template nv_adma_sht =;

static const struct scsi_host_template nv_swncq_sht =;

/*
 * NV SATA controllers have various different problems with hardreset
 * protocol depending on the specific controller and device.
 *
 * GENERIC:
 *
 *  bko11195 reports that link doesn't come online after hardreset on
 *  generic nv's and there have been several other similar reports on
 *  linux-ide.
 *
 *  bko12351#c23 reports that warmplug on MCP61 doesn't work with
 *  softreset.
 *
 * NF2/3:
 *
 *  bko3352 reports nf2/3 controllers can't determine device signature
 *  reliably after hardreset.  The following thread reports detection
 *  failure on cold boot with the standard debouncing timing.
 *
 *  http://thread.gmane.org/gmane.linux.ide/34098
 *
 *  bko12176 reports that hardreset fails to bring up the link during
 *  boot on nf2.
 *
 * CK804:
 *
 *  For initial probing after boot and hot plugging, hardreset mostly
 *  works fine on CK804 but curiously, reprobing on the initial port
 *  by rescanning or rmmod/insmod fails to acquire the initial D2H Reg
 *  FIS in somewhat undeterministic way.
 *
 * SWNCQ:
 *
 *  bko12351 reports that when SWNCQ is enabled, for hotplug to work,
 *  hardreset should be used and hardreset can't report proper
 *  signature, which suggests that mcp5x is closer to nf2 as long as
 *  reset quirkiness is concerned.
 *
 *  bko12703 reports that boot probing fails for intel SSD with
 *  hardreset.  Link fails to come online.  Softreset works fine.
 *
 * The failures are varied but the following patterns seem true for
 * all flavors.
 *
 * - Softreset during boot always works.
 *
 * - Hardreset during boot sometimes fails to bring up the link on
 *   certain comibnations and device signature acquisition is
 *   unreliable.
 *
 * - Hardreset is often necessary after hotplug.
 *
 * So, preferring softreset for boot probing and error handling (as
 * hardreset might bring down the link) but using hardreset for
 * post-boot probing should work around the above issues in most
 * cases.  Define nv_hardreset() which only kicks in for post-boot
 * probing and use it for all variants.
 */
static struct ata_port_operations nv_generic_ops =;

static struct ata_port_operations nv_nf2_ops =;

static struct ata_port_operations nv_ck804_ops =;

static struct ata_port_operations nv_adma_ops =;

static struct ata_port_operations nv_swncq_ops =;

struct nv_pi_priv {};

#define NV_PI_PRIV(_irq_handler, _sht)

static const struct ata_port_info nv_port_info[] =;

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION();

static bool adma_enabled;
static bool swncq_enabled =;
static bool msi_enabled;

static void nv_adma_register_mode(struct ata_port *ap)
{}

static void nv_adma_mode(struct ata_port *ap)
{}

static int nv_adma_device_configure(struct scsi_device *sdev,
		struct queue_limits *lim)
{}

static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc)
{}

static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{}

static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
{}

static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
{}

static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
{}

static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
{}

static void nv_adma_freeze(struct ata_port *ap)
{}

static void nv_adma_thaw(struct ata_port *ap)
{}

static void nv_adma_irq_clear(struct ata_port *ap)
{}

static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
{}

static int nv_adma_port_start(struct ata_port *ap)
{}

static void nv_adma_port_stop(struct ata_port *ap)
{}

#ifdef CONFIG_PM
static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg)
{}

static int nv_adma_port_resume(struct ata_port *ap)
{}
#endif

static void nv_adma_setup_port(struct ata_port *ap)
{}

static int nv_adma_host_init(struct ata_host *host)
{}

static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
			      struct scatterlist *sg,
			      int idx,
			      struct nv_adma_prd *aprd)
{}

static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
{}

static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
{}

static enum ata_completion_errors nv_adma_qc_prep(struct ata_queued_cmd *qc)
{}

static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
{}

static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
{}

static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
{}

static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance)
{}

static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
{}

static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{}

static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{}

static int nv_hardreset(struct ata_link *link, unsigned int *class,
			unsigned long deadline)
{}

static void nv_nf2_freeze(struct ata_port *ap)
{}

static void nv_nf2_thaw(struct ata_port *ap)
{}

static void nv_ck804_freeze(struct ata_port *ap)
{}

static void nv_ck804_thaw(struct ata_port *ap)
{}

static void nv_mcp55_freeze(struct ata_port *ap)
{}

static void nv_mcp55_thaw(struct ata_port *ap)
{}

static void nv_adma_error_handler(struct ata_port *ap)
{}

static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
{}

static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap)
{}

static void nv_swncq_fis_reinit(struct ata_port *ap)
{}

static void nv_swncq_pp_reinit(struct ata_port *ap)
{}

static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis)
{}

static void __ata_bmdma_stop(struct ata_port *ap)
{}

static void nv_swncq_ncq_stop(struct ata_port *ap)
{}

static void nv_swncq_error_handler(struct ata_port *ap)
{}

#ifdef CONFIG_PM
static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg)
{}

static int nv_swncq_port_resume(struct ata_port *ap)
{}
#endif

static void nv_swncq_host_init(struct ata_host *host)
{}

static int nv_swncq_device_configure(struct scsi_device *sdev,
		struct queue_limits *lim)
{}

static int nv_swncq_port_start(struct ata_port *ap)
{}

static enum ata_completion_errors nv_swncq_qc_prep(struct ata_queued_cmd *qc)
{}

static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
{}

static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
					  struct ata_queued_cmd *qc)
{}

static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc)
{}

static void nv_swncq_hotplug(struct ata_port *ap, u32 fis)
{}

static int nv_swncq_sdbfis(struct ata_port *ap)
{}

static inline u32 nv_swncq_tag(struct ata_port *ap)
{}

static void nv_swncq_dmafis(struct ata_port *ap)
{}

static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
{}

static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
{}

static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{}

#ifdef CONFIG_PM_SLEEP
static int nv_pci_device_resume(struct pci_dev *pdev)
{}
#endif

static void nv_ck804_host_stop(struct ata_host *host)
{}

static void nv_adma_host_stop(struct ata_host *host)
{}

module_pci_driver();

module_param_named(adma, adma_enabled, bool, 0444);
MODULE_PARM_DESC();
module_param_named(swncq, swncq_enabled, bool, 0444);
MODULE_PARM_DESC();
module_param_named(msi, msi_enabled, bool, 0444);
MODULE_PARM_DESC();