Newer
Older
/*
* Driver for the Micron P320 SSD
* Copyright (C) 2011 Micron Technology, Inc.
*
* Portions of this code were derived from works subjected to the
* following copyright:
* Copyright (C) 2009 Integrated Device Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/ata.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/uaccess.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <../drivers/ata/ahci.h>
#include <linux/debugfs.h>
#include "mtip32xx.h"
#define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32)
#define HW_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (MTIP_MAX_SG * 16))
#define HW_CMD_TBL_AR_SZ (HW_CMD_TBL_SZ * MTIP_MAX_COMMAND_SLOTS)
#define HW_PORT_PRIV_DMA_SZ \
(HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ)
#define HOST_CAP_NZDMA (1 << 19)
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#define HOST_HSORG 0xFC
#define HSORG_DISABLE_SLOTGRP_INTR (1<<24)
#define HSORG_DISABLE_SLOTGRP_PXIS (1<<16)
#define HSORG_HWREV 0xFF00
#define HSORG_STYLE 0x8
#define HSORG_SLOTGROUPS 0x7
#define PORT_COMMAND_ISSUE 0x38
#define PORT_SDBV 0x7C
#define PORT_OFFSET 0x100
#define PORT_MEM_SIZE 0x80
#define PORT_IRQ_ERR \
(PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | \
PORT_IRQ_PHYRDY | PORT_IRQ_UNK_FIS | PORT_IRQ_BAD_PMP | \
PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR | PORT_IRQ_IF_NONFATAL | \
PORT_IRQ_OVERFLOW)
#define PORT_IRQ_LEGACY \
(PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
#define PORT_IRQ_HANDLED \
(PORT_IRQ_SDB_FIS | PORT_IRQ_LEGACY | \
PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR | \
PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)
#define DEF_PORT_IRQ \
(PORT_IRQ_ERR | PORT_IRQ_LEGACY | PORT_IRQ_SDB_FIS)
/* product numbers */
#define MTIP_PRODUCT_UNKNOWN 0x00
#define MTIP_PRODUCT_ASICFPGA 0x11
/* Device instance number, incremented each time a device is probed. */
static int instance;
/*
* Global variable used to hold the major block device number
* allocated in mtip_init().
*/
static struct dentry *dfs_parent;
static DEFINE_SPINLOCK(rssd_index_lock);
static DEFINE_IDA(rssd_index_ida);
static int mtip_block_initialize(struct driver_data *dd);
struct mtip_compat_ide_task_request_s {
__u8 io_ports[8];
__u8 hob_ports[8];
ide_reg_valid_t out_flags;
ide_reg_valid_t in_flags;
int data_phase;
int req_cmd;
compat_ulong_t out_size;
compat_ulong_t in_size;
};
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* This function check_for_surprise_removal is called
* while card is removed from the system and it will
* read the vendor id from the configration space
*
* @pdev Pointer to the pci_dev structure.
*
* return value
* true if device removed, else false
*/
static bool mtip_check_surprise_removal(struct pci_dev *pdev)
{
u16 vendor_id = 0;
/* Read the vendorID from the configuration space */
pci_read_config_word(pdev, 0x00, &vendor_id);
if (vendor_id == 0xFFFF)
return true; /* device removed */
return false; /* device present */
}
/*
* This function is called for clean the pending command in the
* command slot during the surprise removal of device and return
* error to the upper layer.
*
* @dd Pointer to the DRIVER_DATA structure.
*
* return value
* None
*/
static void mtip_command_cleanup(struct driver_data *dd)
{
int group = 0, commandslot = 0, commandindex = 0;
struct mtip_cmd *command;
struct mtip_port *port = dd->port;
static int in_progress;
if (in_progress)
return;
in_progress = 1;
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
for (group = 0; group < 4; group++) {
for (commandslot = 0; commandslot < 32; commandslot++) {
if (!(port->allocated[group] & (1 << commandslot)))
continue;
commandindex = group << 5 | commandslot;
command = &port->commands[commandindex];
if (atomic_read(&command->active)
&& (command->async_callback)) {
command->async_callback(command->async_data,
-ENODEV);
command->async_callback = NULL;
command->async_data = NULL;
}
dma_unmap_sg(&port->dd->pdev->dev,
command->sg,
command->scatter_ents,
command->direction);
}
}
up(&port->cmd_slot);
set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag);
/*
* Obtain an empty command slot.
*
* This function needs to be reentrant since it could be called
* at the same time on multiple CPUs. The allocation of the
* command slot must be atomic.
*
* @port Pointer to the port data structure.
*
* return value
* >= 0 Index of command slot obtained.
* -1 No command slots available.
*/
static int get_slot(struct mtip_port *port)
{
int slot, i;
unsigned int num_command_slots = port->dd->slot_groups * 32;
/*
Loading
Loading full blame...