Commit a5a5e2d1 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

Add new Megaraid driver version 2.20.0.1

From: Mukker, Atul <Atulm@lsil.com>

This is a complete re-write to replace the now obsoleted megaraid2
driver.
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 44d90463
### Version 2.00.3 Release Date : Mon Jun 21 19:53:54 EDT 2004 - Atul Mukker <atulm@lsil.com>
Wed Jan 29 09:13:44 EST 200 - Atul Mukker <atulm@lsil.com> Current Version : 2.20.0.0
i. Change the handshake in ISR while acknowledging interrupts. Write the Older Version : megaraid 2.20.0.rc2 and 2.00.3
valid interrupt pattern 0x10001234 as soon as it is read from the
outdoor register. In existing driver and on certain platform, invalid
command ids were being returned.
Also, do not wait on status be become 0xFF, since FW can return this i. Independent module to interact with userland applications and
status in certain circumstances. multiplex command to low level RAID module(s).
Initialize the numstatus field of mailbox to 0xFF so that we can wait "Shared code in a third module, a "library module", is an acceptable
on this wait in next interrupt. Firmware does not change its value solution. modprobe automatically loads dependent modules, so users
unless there are some status to be posted running "modprobe driver1" or "modprobe driver2" would automatically
load the shared library module."
ii. Specify the logical drive number while issuing the RESERVATION_STATUS - Jeff Garzik <jgarzik@pobox.com> 02.25.2004 LKML
iii. Reduce the default mailbox busy wait time from 300us to 10us. This is "As Jeff hinted, if your userspace<->driver API is consistent between
done to avaoid a possible deadlock in FW because of longer bust waits. your new MPT-based RAID controllers and your existing megaraid driver,
then perhaps you need a single small helper module (lsiioctl or some
better name), loaded by both mptraid and megaraid automatically, which
handles registering the /dev/megaraid node dynamically. In this case,
both mptraid and megaraid would register with lsiioctl for each
adapter discovered, and lsiioctl would essentially be a switch,
redirecting userspace tool ioctls to the appropriate driver."
iv. The max outstanding commands are reduced to 126 because that't the - Matt Domsch <Matt_Domsch@dell.com> 02.25.2004 LKML
safest value on all FW.
v. Number of sectors per IO are reduced to 128 (64kb), becuase FW needs ii. Remove C99 initializations from pci_device id.
resources in special circumstances like check consistency, rebuilds
etc.
vi. max_commands is no longer a module parameter because of iv. "pci_id_table_g would be much more readable when not using C99
initializers.
PCI table doesn't change, there's lots of users that prefer the more
readable variant. And it's really far less and much easier to grok
lines without C99 initializers."
### Version: 2.00.2 - Christoph Hellwig <hch@infradead.org>, 05.28.2004 linux-scsi
i. Intermediate release with kernel specific code
iii. Many fixes as suggested by Christoph Hellwig <hch@infradead.org> on
linux-scsi, 05.28.2004
### Version: 2.00.1i iv. We now support up to 32 parallel ioctl commands instead of current 1.
Wed Dec 4 14:34:51 EST 2002 - Atul Mukker <atulm@lsil.com> There is a conscious effort to let memory allocation not fail for ioctl
i. Making the older IO based controllers to work with this driver commands.
v. Do away with internal memory management. Use pci_pool_(create|alloc)
instead.
### Version 2.00.1 vi. Kill tasklet when unloading the driver.
Fri Nov 15 10:59:44 EST 2002 - Atul Mukker <atulm@lsil.com>
i. Release host lock before issuing internal command to reset vii. Do not use "host_lock', driver has fine-grain locks now to protect all
reservations in megaraid_reset() and reacquire after internal command data structures.
is completed.
viii. Optimize the build scatter-gather list routine. The callers already
know the data transfer address and length.
ix. Better implementation of error handling and recovery. Driver now
performs extended errors recovery for instances like scsi cable pull.
x. Disassociate the management commands with an overlaid scsi command.
Driver now treats the mangement packets as special packets and has a
dedicated callback routine.
Notes on Management Module
~~~~~~~~~~~~~~~~~~~~~~~~~~
Overview:
--------
Different classes of controllers from LSI Logic, accept and respond to the
user applications in a similar way. They understand the same firmware control
commands. Furthermore, the applications also can treat different classes of
the controllers uniformly. Hence it is logical to have a single module that
interefaces with the applications on one side and all the low level drivers
on the other.
The advantages, though obvious, are listed for completeness:
i. Avoid duplicate code from the low level drivers.
ii. Unburden the low level drivers from having to export the
character node device and related handling.
iii. Implement any policy mechanisms in one place.
iv. Applications have to interface with only module instead of
multiple low level drivers.
Currently this module (called Common Management Module) is used only to issue
ioctl commands. But this module is envisioned to handle all user space level
interactions. So any 'proc', 'sysfs' implementations will be localized in this
common module.
Credits:
-------
"Shared code in a third module, a "library module", is an acceptable
solution. modprobe automatically loads dependent modules, so users
running "modprobe driver1" or "modprobe driver2" would automatically
load the shared library module."
- Jeff Garzik (jgarzik@pobox.com), 02.25.2004 LKML
"As Jeff hinted, if your userspace<->driver API is consistent between
your new MPT-based RAID controllers and your existing megaraid driver,
then perhaps you need a single small helper module (lsiioctl or some
better name), loaded by both mptraid and megaraid automatically, which
handles registering the /dev/megaraid node dynamically. In this case,
both mptraid and megaraid would register with lsiioctl for each
adapter discovered, and lsiioctl would essentially be a switch,
redirecting userspace tool ioctls to the appropriate driver."
- Matt Domsch, (Matt_Domsch@dell.com), 02.25.2004 LKML
Design:
------
The Common Management Module is implemented in megaraid_mm.[ch] files. This
module acts as a registry for low level hba drivers. The low level drivers
(currently only megaraid) register each controller with the common module.
The applications interface with the common module via the character device
node exported by the module.
The lower level drivers now understand only a new improved ioctl packet called
uioc_t. The management module converts the older ioctl packets from the older
applications into uioc_t. After driver handles the uioc_t, the common module
will convert that back into the old format before returning to applications.
As new applications evolve and replace the old ones, the old packet format
will be retired.
Common module dedicates one uioc_t packet to each controller registered. This
can easily be more than one. But since megaraid is the only low level driver
today, and it can handle only one ioctl, there is no reason to have more. But
as new controller classes get added, this will be tuned appropriately.
...@@ -203,8 +203,22 @@ ...@@ -203,8 +203,22 @@
1000 0530 MegaRAID 530 SCSI 320-0X RAID Controller 1000 0530 MegaRAID 530 SCSI 320-0X RAID Controller
1000 0531 MegaRAID 531 SCSI 320-4X RAID Controller 1000 0531 MegaRAID 531 SCSI 320-4X RAID Controller
1000 0532 MegaRAID 532 SCSI 320-2X RAID Controller 1000 0532 MegaRAID 532 SCSI 320-2X RAID Controller
1028 0533 PowerEgde Expandable RAID Controller 4/QC 1028 0531 PowerEgde Expandable RAID Controller 4/QC
8086 0532 Storage RAID Controller SRCU42X 8086 0530 MegaRAID Intel RAID Controller SRCZCRX
8086 0532 MegaRAID Intel RAID Controller SRCU42X
0408 MegaRAID
1000 0001 MegaRAID SCSI 320-1E RAID Controller
1000 0002 MegaRAID SCSI 320-2E RAID Controller
1028 0001 Dell PowerEdge RAID Controller PERC4e/SC
1028 0002 Dell PowerEdge RAID Controller PERC4e/DC
1734 1065 FSC MegaRAID PCI Express ROMB
8086 0002 MegaRAID Intel RAID Controller SRCU42E
0409 MegaRAID
1000 3004 MegaRAID SATA 300-4X RAID Controller
1000 3008 MegaRAID SATA 300-8X RAID Controller
8086 3008 MegaRAID Intel RAID Controller SRCS28X
8086 3431 MegaRAID Intel RAID Controller Alief SROMBU42E
8086 3499 MegaRAID Intel RAID Controller Harwich SROMBU42E
0621 FC909 Fibre Channel Adapter 0621 FC909 Fibre Channel Adapter
0622 FC929 Fibre Channel Adapter 0622 FC929 Fibre Channel Adapter
1000 1020 44929 O Dual Fibre Channel card 1000 1020 44929 O Dual Fibre Channel card
...@@ -228,13 +242,15 @@ ...@@ -228,13 +242,15 @@
1960 MegaRAID 1960 MegaRAID
1000 0518 MegaRAID 518 SCSI 320-2 Controller 1000 0518 MegaRAID 518 SCSI 320-2 Controller
1000 0520 MegaRAID 520 SCSI 320-1 Controller 1000 0520 MegaRAID 520 SCSI 320-1 Controller
1000 0522 MegaRAID 522 i4133 RAID Controller 1000 0522 MegaRAID 522 i4 133 RAID Controller
1000 0523 MegaRAID SATA 150-6 RAID Controller 1000 0523 MegaRAID SATA 150-6 RAID Controller
1000 4523 MegaRAID SATA 150-4 RAID Controller 1000 4523 MegaRAID SATA 150-4 RAID Controller
1000 a520 MegaRAID ZCR SCSI 320-0 Controller 1000 a520 MegaRAID ZCR SCSI 320-0 Controller
1028 0518 MegaRAID 518 DELL PERC 4/DC RAID Controller 1028 0518 MegaRAID 518 DELL PERC 4/DC RAID Controller
1028 0520 MegaRAID 520 DELL PERC 4/SC RAID Controller 1028 0520 MegaRAID 520 DELL PERC 4/SC RAID Controller
1028 0531 PowerEdge Expandable RAID Controller 4/QC 1028 0531 PowerEdge Expandable RAID Controller 4/QC
8086 0520 MegaRAID Intel RAID Controller SRCU41L
8086 0523 MegaRAID Intel RAID Controller SRCS16
1001 Kolter Electronic 1001 Kolter Electronic
0010 PCI 1616 Measurement card with 32 digital I/O lines 0010 PCI 1616 Measurement card with 32 digital I/O lines
0011 OPTO-PCI Opto-Isolated digital I/O board 0011 OPTO-PCI Opto-Isolated digital I/O board
...@@ -1210,6 +1226,12 @@ ...@@ -1210,6 +1226,12 @@
1028 014a PowerEdge Expandable RAID Controller 4/Di 1028 014a PowerEdge Expandable RAID Controller 4/Di
1028 014c MegaRAID DELL PERC 4/Di RAID On Motherboard 1028 014c MegaRAID DELL PERC 4/Di RAID On Motherboard
1028 014d MegaRAID DELL PERC 4/Di RAID On Motherboard 1028 014d MegaRAID DELL PERC 4/Di RAID On Motherboard
0013 PowerEdge Expandable RAID controller 4
1028 016c PowerEdge Expandable RAID Controller 4e/Si
1028 016d PowerEdge Expandable RAID Controller 4e/Di
1028 016e PowerEdge Expandable RAID Controller 4e/Di
1028 016f PowerEdge Expandable RAID Controller 4e/Di
1028 0170 PowerEdge Expandable RAID Controller 4e/Di
1029 Siemens Nixdorf IS 1029 Siemens Nixdorf IS
102a LSI Logic 102a LSI Logic
0000 HYDRA 0000 HYDRA
......
...@@ -395,15 +395,7 @@ config SCSI_IN2000 ...@@ -395,15 +395,7 @@ config SCSI_IN2000
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called in2000. module will be called in2000.
config SCSI_MEGARAID source "drivers/scsi/megaraid/Kconfig.megaraid"
tristate "AMI MegaRAID support"
depends on PCI && SCSI
help
This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
and 467 SCSI host adapters.
To compile this driver as a module, choose M here: the
module will be called megaraid.
config SCSI_SATA config SCSI_SATA
bool "Serial ATA (SATA) support" bool "Serial ATA (SATA) support"
......
...@@ -95,7 +95,8 @@ obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o ...@@ -95,7 +95,8 @@ obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o
obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_EATA) += eata.o
obj-$(CONFIG_SCSI_DC395x) += dc395x.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o
obj-$(CONFIG_SCSI_DC390T) += tmscsim.o obj-$(CONFIG_SCSI_DC390T) += tmscsim.o
obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o obj-$(CONFIG_SCSI_ACARD) += atp870u.o
obj-$(CONFIG_SCSI_SUNESP) += esp.o obj-$(CONFIG_SCSI_SUNESP) += esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o obj-$(CONFIG_SCSI_GDTH) += gdth.o
......
config MEGARAID_NEWGEN
bool "LSI Logic New Generation RAID Device Drivers"
depends on PCI && SCSI
default y
help
LSI Logic RAID Device Drivers
config MEGARAID_MM
tristate "LSI Logic Management Module (New Driver)"
depends on PCI && SCSI && MEGARAID_NEWGEN
default m
help
Management Module provides ioctl, sysfs support for LSI Logic
RAID controllers.
To compile this driver as a module, choose M here: the
module will be called megaraid_mm
config MEGARAID_MAILBOX
tristate "LSI Logic MegaRAID Driver (New Driver)"
depends on PCI && SCSI && MEGARAID_MM
default $MEGARAID_MM
help
List of supported controllers
OEM Product Name VID :DID :SVID:SSID
--- ------------ ---- ---- ---- ----
Dell PERC3/QC 101E:1960:1028:0471
Dell PERC3/DC 101E:1960:1028:0493
Dell PERC3/SC 101E:1960:1028:0475
Dell PERC3/Di 1028:000E:1028:0123
Dell PERC4/SC 1000:1960:1028:0520
Dell PERC4/DC 1000:1960:1028:0518
Dell PERC4/QC 1000:0407:1028:0531
Dell PERC4/Di 1028:000F:1028:014A
Dell PERC 4e/Si 1028:0013:1028:016c
Dell PERC 4e/Di 1028:0013:1028:016d
Dell PERC 4e/Di 1028:0013:1028:016e
Dell PERC 4e/Di 1028:0013:1028:016f
Dell PERC 4e/Di 1028:0013:1028:0170
Dell PERC 4e/DC 1000:0408:1028:0002
Dell PERC 4e/SC 1000:0408:1028:0001
LSI MegaRAID SCSI 320-0 1000:1960:1000:A520
LSI MegaRAID SCSI 320-1 1000:1960:1000:0520
LSI MegaRAID SCSI 320-2 1000:1960:1000:0518
LSI MegaRAID SCSI 320-0X 1000:0407:1000:0530
LSI MegaRAID SCSI 320-2X 1000:0407:1000:0532
LSI MegaRAID SCSI 320-4X 1000:0407:1000:0531
LSI MegaRAID SCSI 320-1E 1000:0408:1000:0001
LSI MegaRAID SCSI 320-2E 1000:0408:1000:0002
LSI MegaRAID SATA 150-2 1095:3112:1000:0534
LSI MegaRAID SATA 150-4 1000:1960:1000:4523
LSI MegaRAID SATA 150-6 1000:1960:1000:0523
LSI MegaRAID SATA 150-4X 1000:0409:1000:1504
LSI MegaRAID SATA 150-8X 1000:0409:1000:1508
INTEL RAID Controller SRCU42X 1000:0407:8086:0532
INTEL RAID Controller SRCS16 1000:1960:8086:0523
INTEL RAID Controller SRCU42E 1000:0408:8086:0002
INTEL RAID Controller SRCZCRX 1000:0407:8086:0530
INTEL RAID Controller SRCS28X 1000:0409:8086:3008
INTEL RAID Controller SROMBU42E 1000:0408:8086:3431
INTEL RAID Controller SROMBU42E 1000:0408:8086:3499
INTEL RAID Controller SRCU51L 1000:1960:8086:0520
FSC MegaRAID PCI Express ROMB 1000:0408:1734:1065
To compile this driver as a module, choose M here: the
module will be called megaraid_mbox
if MEGARAID_NEWGEN=n
config MEGARAID_LEGACY
tristate "LSI Logic Legacy MegaRAID Driver"
depends on PCI && SCSI
default m
help
This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490
and 467 SCSI host adapters. This driver also support the all U320
RAID controllers
To compile this driver as a module, choose M here: the
module will be called megaraid
endif
obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
/*
*
* Linux MegaRAID Unified device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : mbox_defs.h
*
*/
#ifndef _MRAID_MBOX_DEFS_H_
#define _MRAID_MBOX_DEFS_H_
#include <linux/types.h>
/*
* Commands and states for mailbox based controllers
*/
#define MBOXCMD_LREAD 0x01
#define MBOXCMD_LWRITE 0x02
#define MBOXCMD_PASSTHRU 0x03
#define MBOXCMD_ADPEXTINQ 0x04
#define MBOXCMD_ADAPTERINQ 0x05
#define MBOXCMD_LREAD64 0xA7
#define MBOXCMD_LWRITE64 0xA8
#define MBOXCMD_PASSTHRU64 0xC3
#define MBOXCMD_EXTPTHRU 0xE3
#define MAIN_MISC_OPCODE 0xA4
#define GET_MAX_SG_SUPPORT 0x01
#define SUPPORT_EXT_CDB 0x16
#define FC_NEW_CONFIG 0xA1
#define NC_SUBOP_PRODUCT_INFO 0x0E
#define NC_SUBOP_ENQUIRY3 0x0F
#define ENQ3_GET_SOLICITED_FULL 0x02
#define OP_DCMD_READ_CONFIG 0x04
#define NEW_READ_CONFIG_8LD 0x67
#define READ_CONFIG_8LD 0x07
#define FLUSH_ADAPTER 0x0A
#define FLUSH_SYSTEM 0xFE
/*
* Command for random deletion of logical drives
*/
#define FC_DEL_LOGDRV 0xA4
#define OP_SUP_DEL_LOGDRV 0x2A
#define OP_GET_LDID_MAP 0x18
#define OP_DEL_LOGDRV 0x1C
/*
* BIOS commands
*/
#define IS_BIOS_ENABLED 0x62
#define GET_BIOS 0x01
#define CHNL_CLASS 0xA9
#define GET_CHNL_CLASS 0x00
#define SET_CHNL_CLASS 0x01
#define CH_RAID 0x01
#define CH_SCSI 0x00
#define BIOS_PVT_DATA 0x40
#define GET_BIOS_PVT_DATA 0x00
/*
* Commands to support clustering
*/
#define GET_TARGET_ID 0x7D
#define CLUSTER_OP 0x70
#define GET_CLUSTER_MODE 0x02
#define CLUSTER_CMD 0x6E
#define RESERVE_LD 0x01
#define RELEASE_LD 0x02
#define RESET_RESERVATIONS 0x03
#define RESERVATION_STATUS 0x04
#define RESERVE_PD 0x05
#define RELEASE_PD 0x06
/*
* Module battery status
*/
#define BATTERY_MODULE_MISSING 0x01
#define BATTERY_LOW_VOLTAGE 0x02
#define BATTERY_TEMP_HIGH 0x04
#define BATTERY_PACK_MISSING 0x08
#define BATTERY_CHARGE_MASK 0x30
#define BATTERY_CHARGE_DONE 0x00
#define BATTERY_CHARGE_INPROG 0x10
#define BATTERY_CHARGE_FAIL 0x20
#define BATTERY_CYCLES_EXCEEDED 0x40
/*
* Physical drive states.
*/
#define PDRV_UNCNF 0
#define PDRV_ONLINE 3
#define PDRV_FAILED 4
#define PDRV_RBLD 5
#define PDRV_HOTSPARE 6
/*
* Raid logical drive states.
*/
#define RDRV_OFFLINE 0
#define RDRV_DEGRADED 1
#define RDRV_OPTIMAL 2
#define RDRV_DELETED 3
/*
* Read, write and cache policies
*/
#define NO_READ_AHEAD 0
#define READ_AHEAD 1
#define ADAP_READ_AHEAD 2
#define WRMODE_WRITE_THRU 0
#define WRMODE_WRITE_BACK 1
#define CACHED_IO 0
#define DIRECT_IO 1
#define MAX_LOGICAL_DRIVES_8LD 8
#define MAX_LOGICAL_DRIVES_40LD 40
#define FC_MAX_PHYSICAL_DEVICES 256
#define MAX_MBOX_CHANNELS 5
#define MAX_MBOX_TARGET 15
#define MBOX_MAX_PHYSICAL_DRIVES MAX_MBOX_CHANNELS*MAX_MBOX_TARGET
#define MAX_ROW_SIZE_40LD 32
#define MAX_ROW_SIZE_8LD 8
#define SPAN_DEPTH_8_SPANS 8
#define SPAN_DEPTH_4_SPANS 4
#define MAX_REQ_SENSE_LEN 0x20
/**
* struct mbox_t - Driver and f/w handshake structure.
* @cmd : firmware command
* @cmdid : command id
* @numsectors : number of sectors to be transferred
* @lba : Logical Block Address on LD
* @xferaddr : DMA address for data transfer
* @logdrv : logical drive number
* @numsge : number of scatter gather elements in sg list
* @resvd : reserved
* @busy : f/w busy, must wait to issue more commands.
* @numstatus : number of commands completed.
* @status : status of the commands completed
* @completed : array of completed command ids.
* @poll : poll and ack sequence
* @ack : poll and ack sequence
*
* The central handshake structure between the driver and the firmware. This
* structure must be allocated by the driver and aligned at 8-byte boundary.
*/
#define MBOX_MAX_FIRMWARE_STATUS 46
typedef struct {
uint8_t cmd;
uint8_t cmdid;
uint16_t numsectors;
uint32_t lba;
uint32_t xferaddr;
uint8_t logdrv;
uint8_t numsge;
uint8_t resvd;
uint8_t busy;
uint8_t numstatus;
uint8_t status;
uint8_t completed[MBOX_MAX_FIRMWARE_STATUS];
uint8_t poll;
uint8_t ack;
} __attribute__ ((packed)) mbox_t;
/**
* mbox64_t - 64-bit extension for the mailbox
* @segment_lo : the low 32-bits of the address of the scatter-gather list
* @segment_hi : the upper 32-bits of the address of the scatter-gather list
* @mbox : 32-bit mailbox, whose xferadder field must be set to
* 0xFFFFFFFF
*
* This is the extension of the 32-bit mailbox to be able to perform DMA
* beyond 4GB address range.
*/
typedef struct {
uint32_t xferaddr_lo;
uint32_t xferaddr_hi;
mbox_t mbox32;
} __attribute__ ((packed)) mbox64_t;
/*
* mailbox structure used for internal commands
*/
typedef struct {
u8 cmd;
u8 cmdid;
u8 opcode;
u8 subopcode;
u32 lba;
u32 xferaddr;
u8 logdrv;
u8 rsvd[3];
u8 numstatus;
u8 status;
} __attribute__ ((packed)) int_mbox_t;
/**
* mraid_passthru_t - passthru structure to issue commands to physical devices
* @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr
* @ars : set if ARS required after check condition
* @islogical : set if command meant for logical devices
* @logdrv : logical drive number if command for LD
* @channel : Channel on which physical device is located
* @target : SCSI target of the device
* @queuetag : unused
* @queueaction : unused
* @cdb : SCSI CDB
* @cdblen : length of the CDB
* @reqsenselen : amount of request sense data to be returned
* @reqsensearea : Sense information buffer
* @numsge : number of scatter-gather elements in the sg list
* @scsistatus : SCSI status of the command completed.
* @dataxferaddr : DMA data transfer address
* @dataxferlen : amount of the data to be transferred.
*/
typedef struct {
uint8_t timeout :3;
uint8_t ars :1;
uint8_t reserved :3;
uint8_t islogical :1;
uint8_t logdrv;
uint8_t channel;
uint8_t target;
uint8_t queuetag;
uint8_t queueaction;
uint8_t cdb[10];
uint8_t cdblen;
uint8_t reqsenselen;
uint8_t reqsensearea[MAX_REQ_SENSE_LEN];
uint8_t numsge;
uint8_t scsistatus;
uint32_t dataxferaddr;
uint32_t dataxferlen;
} __attribute__ ((packed)) mraid_passthru_t;
typedef struct {
uint32_t dataxferaddr_lo;
uint32_t dataxferaddr_hi;
mraid_passthru_t pthru32;
} __attribute__ ((packed)) mega_passthru64_t;
/**
* mraid_epassthru_t - passthru structure to issue commands to physical devices
* @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr
* @ars : set if ARS required after check condition
* @rsvd1 : reserved field
* @cd_rom : (?)
* @rsvd2 : reserved field
* @islogical : set if command meant for logical devices
* @logdrv : logical drive number if command for LD
* @channel : Channel on which physical device is located
* @target : SCSI target of the device
* @queuetag : unused
* @queueaction : unused
* @cdblen : length of the CDB
* @rsvd3 : reserved field
* @cdb : SCSI CDB
* @numsge : number of scatter-gather elements in the sg list
* @status : SCSI status of the command completed.
* @reqsenselen : amount of request sense data to be returned
* @reqsensearea : Sense information buffer
* @rsvd4 : reserved field
* @dataxferaddr : DMA data transfer address
* @dataxferlen : amount of the data to be transferred.
*/
typedef struct {
uint8_t timeout :3;
uint8_t ars :1;
uint8_t rsvd1 :1;
uint8_t cd_rom :1;
uint8_t rsvd2 :1;
uint8_t islogical :1;
uint8_t logdrv;
uint8_t channel;
uint8_t target;
uint8_t queuetag;
uint8_t queueaction;
uint8_t cdblen;
uint8_t rsvd3;
uint8_t cdb[16];
uint8_t numsge;
uint8_t status;
uint8_t reqsenselen;
uint8_t reqsensearea[MAX_REQ_SENSE_LEN];
uint8_t rsvd4;
uint32_t dataxferaddr;
uint32_t dataxferlen;
} __attribute__ ((packed)) mraid_epassthru_t;
/**
* mraid_pinfo_t - product info, static information about the controller
* @data_size : current size in bytes (not including resvd)
* @config_signature : Current value is 0x00282008
* @fw_version : Firmware version
* @bios_version : version of the BIOS
* @product_name : Name given to the controller
* @max_commands : Maximum concurrent commands supported
* @nchannels : Number of SCSI Channels detected
* @fc_loop_present : Number of Fibre Loops detected
* @mem_type : EDO, FPM, SDRAM etc
* @signature :
* @dram_size : In terms of MB
* @subsysid : device PCI subsystem ID
* @subsysvid : device PCI subsystem vendor ID
* @notify_counters :
* @pad1k : 135 + 889 resvd = 1024 total size
*
* This structures holds the information about the controller which is not
* expected to change dynamically.
*
* The current value of config signature is 0x00282008:
* 0x28 = MAX_LOGICAL_DRIVES,
* 0x20 = Number of stripes and
* 0x08 = Number of spans
*/
typedef struct {
uint32_t data_size;
uint32_t config_signature;
uint8_t fw_version[16];
uint8_t bios_version[16];
uint8_t product_name[80];
uint8_t max_commands;
uint8_t nchannels;
uint8_t fc_loop_present;
uint8_t mem_type;
uint32_t signature;
uint16_t dram_size;
uint16_t subsysid;
uint16_t subsysvid;
uint8_t notify_counters;
uint8_t pad1k[889];
} __attribute__ ((packed)) mraid_pinfo_t;
/**
* mraid_notify_t - the notification structure
* @global_counter : Any change increments this counter
* @param_counter : Indicates any params changed
* @param_id : Param modified - defined below
* @param_val : New val of last param modified
* @write_config_counter : write config occurred
* @write_config_rsvd :
* @ldrv_op_counter : Indicates ldrv op started/completed
* @ldrv_opid : ldrv num
* @ldrv_opcmd : ldrv operation - defined below
* @ldrv_opstatus : status of the operation
* @ldrv_state_counter : Indicates change of ldrv state
* @ldrv_state_id : ldrv num
* @ldrv_state_new : New state
* @ldrv_state_old : old state
* @pdrv_state_counter : Indicates change of ldrv state
* @pdrv_state_id : pdrv id
* @pdrv_state_new : New state
* @pdrv_state_old : old state
* @pdrv_fmt_counter : Indicates pdrv format started/over
* @pdrv_fmt_id : pdrv id
* @pdrv_fmt_val : format started/over
* @pdrv_fmt_rsvd :
* @targ_xfer_counter : Indicates SCSI-2 Xfer rate change
* @targ_xfer_id : pdrv Id
* @targ_xfer_val : new Xfer params of last pdrv
* @targ_xfer_rsvd :
* @fcloop_id_chg_counter : Indicates loopid changed
* @fcloopid_pdrvid : pdrv id
* @fcloop_id0 : loopid on fc loop 0
* @fcloop_id1 : loopid on fc loop 1
* @fcloop_state_counter : Indicates loop state changed
* @fcloop_state0 : state of fc loop 0
* @fcloop_state1 : state of fc loop 1
* @fcloop_state_rsvd :
*/
typedef struct {
uint32_t global_counter;
uint8_t param_counter;
uint8_t param_id;
uint16_t param_val;
uint8_t write_config_counter;
uint8_t write_config_rsvd[3];
uint8_t ldrv_op_counter;
uint8_t ldrv_opid;
uint8_t ldrv_opcmd;
uint8_t ldrv_opstatus;
uint8_t ldrv_state_counter;
uint8_t ldrv_state_id;
uint8_t ldrv_state_new;
uint8_t ldrv_state_old;
uint8_t pdrv_state_counter;
uint8_t pdrv_state_id;
uint8_t pdrv_state_new;
uint8_t pdrv_state_old;
uint8_t pdrv_fmt_counter;
uint8_t pdrv_fmt_id;
uint8_t pdrv_fmt_val;
uint8_t pdrv_fmt_rsvd;
uint8_t targ_xfer_counter;
uint8_t targ_xfer_id;
uint8_t targ_xfer_val;
uint8_t targ_xfer_rsvd;
uint8_t fcloop_id_chg_counter;
uint8_t fcloopid_pdrvid;
uint8_t fcloop_id0;
uint8_t fcloop_id1;
uint8_t fcloop_state_counter;
uint8_t fcloop_state0;
uint8_t fcloop_state1;
uint8_t fcloop_state_rsvd;
} __attribute__ ((packed)) mraid_notify_t;
/**
* mraid_inquiry3_t - enquiry for device information
*
* @data_size : current size in bytes (not including resvd)
* @notify :
* @notify_rsvd :
* @rebuild_rate : rebuild rate (0% - 100%)
* @cache_flush_int : cache flush interval in seconds
* @sense_alert :
* @drive_insert_count : drive insertion count
* @battery_status :
* @num_ldrv : no. of Log Drives configured
* @recon_state : state of reconstruct
* @ldrv_op_status : logdrv Status
* @ldrv_size : size of each log drv
* @ldrv_prop :
* @ldrv_state : state of log drives
* @pdrv_state : state of phys drvs.
* @pdrv_format :
* @targ_xfer : phys device transfer rate
* @pad1k : 761 + 263reserved = 1024 bytes total size
*/
#define MAX_NOTIFY_SIZE 0x80
#define CUR_NOTIFY_SIZE sizeof(mraid_notify_t)
typedef struct {
uint32_t data_size;
mraid_notify_t notify;
uint8_t notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
uint8_t rebuild_rate;
uint8_t cache_flush_int;
uint8_t sense_alert;
uint8_t drive_insert_count;
uint8_t battery_status;
uint8_t num_ldrv;
uint8_t recon_state[MAX_LOGICAL_DRIVES_40LD / 8];
uint16_t ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8];
uint32_t ldrv_size[MAX_LOGICAL_DRIVES_40LD];
uint8_t ldrv_prop[MAX_LOGICAL_DRIVES_40LD];
uint8_t ldrv_state[MAX_LOGICAL_DRIVES_40LD];
uint8_t pdrv_state[FC_MAX_PHYSICAL_DEVICES];
uint16_t pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16];
uint8_t targ_xfer[80];
uint8_t pad1k[263];
} __attribute__ ((packed)) mraid_inquiry3_t;
/**
* mraid_adapinfo_t - information about the adapter
* @max_commands : max concurrent commands supported
* @rebuild_rate : rebuild rate - 0% thru 100%
* @max_targ_per_chan : max targ per channel
* @nchannels : number of channels on HBA
* @fw_version : firmware version
* @age_of_flash : number of times FW has been flashed
* @chip_set_value : contents of 0xC0000832
* @dram_size : in MB
* @cache_flush_interval : in seconds
* @bios_version :
* @board_type :
* @sense_alert :
* @write_config_count : increase with every configuration change
* @drive_inserted_count : increase with every drive inserted
* @inserted_drive : channel:Id of inserted drive
* @battery_status : bit 0: battery module missing
* bit 1: VBAD
* bit 2: temprature high
* bit 3: battery pack missing
* bit 4,5:
* 00 - charge complete
* 01 - fast charge in progress
* 10 - fast charge fail
* 11 - undefined
* bit 6: counter > 1000
* bit 7: Undefined
* @dec_fault_bus_info :
*/
typedef struct {
uint8_t max_commands;
uint8_t rebuild_rate;
uint8_t max_targ_per_chan;
uint8_t nchannels;
uint8_t fw_version[4];
uint16_t age_of_flash;
uint8_t chip_set_value;
uint8_t dram_size;
uint8_t cache_flush_interval;
uint8_t bios_version[4];
uint8_t board_type;
uint8_t sense_alert;
uint8_t write_config_count;
uint8_t battery_status;
uint8_t dec_fault_bus_info;
} __attribute__ ((packed)) mraid_adapinfo_t;
/**
* mraid_ldrv_info_t - information about the logical drives
* @nldrv : Number of logical drives configured
* @rsvd :
* @size : size of each logical drive
* @prop :
* @state : state of each logical drive
*/
typedef struct {
uint8_t nldrv;
uint8_t rsvd[3];
uint32_t size[MAX_LOGICAL_DRIVES_8LD];
uint8_t prop[MAX_LOGICAL_DRIVES_8LD];
uint8_t state[MAX_LOGICAL_DRIVES_8LD];
} __attribute__ ((packed)) mraid_ldrv_info_t;
/**
* mraid_pdrv_info_t - information about the physical drives
* @pdrv_state : state of each physical drive
*/
typedef struct {
uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES];
uint8_t rsvd;
} __attribute__ ((packed)) mraid_pdrv_info_t;
/**
* mraid_inquiry_t - RAID inquiry, mailbox command 0x05
* @mraid_adapinfo_t : adapter information
* @mraid_ldrv_info_t : logical drives information
* @mraid_pdrv_info_t : physical drives information
*/
typedef struct {
mraid_adapinfo_t adapter_info;
mraid_ldrv_info_t logdrv_info;
mraid_pdrv_info_t pdrv_info;
} __attribute__ ((packed)) mraid_inquiry_t;
/**
* mraid_extinq_t - RAID extended inquiry, mailbox command 0x04
*
* @raid_inq : raid inquiry
* @phys_drv_format :
* @stack_attn :
* @modem_status :
* @rsvd :
*/
typedef struct {
mraid_inquiry_t raid_inq;
uint16_t phys_drv_format[MAX_MBOX_CHANNELS];
uint8_t stack_attn;
uint8_t modem_status;
uint8_t rsvd[2];
} __attribute__ ((packed)) mraid_extinq_t;
/**
* adap_device_t - device information
* @channel : channel fpor the device
* @target : target ID of the device
*/
typedef struct {
uint8_t channel;
uint8_t target;
}__attribute__ ((packed)) adap_device_t;
/**
* adap_span_40ld_t - 40LD span
* @start_blk : starting block
* @num_blks : number of blocks
*/
typedef struct {
uint32_t start_blk;
uint32_t num_blks;
adap_device_t device[MAX_ROW_SIZE_40LD];
}__attribute__ ((packed)) adap_span_40ld_t;
/**
* adap_span_8ld_t - 8LD span
* @start_blk : starting block
* @num_blks : number of blocks
*/
typedef struct {
uint32_t start_blk;
uint32_t num_blks;
adap_device_t device[MAX_ROW_SIZE_8LD];
}__attribute__ ((packed)) adap_span_8ld_t;
/**
* logdrv_param_t - logical drives parameters
*
* @span_depth : total number of spans
* @level : RAID level
* @read_ahead : read ahead, no read ahead, adaptive read ahead
* @stripe_sz : encoded stripe size
* @status : status of the logical drive
* @write_mode : write mode, write_through/write_back
* @direct_io : direct io or through cache
* @row_size : number of stripes in a row
*/
typedef struct {
uint8_t span_depth;
uint8_t level;
uint8_t read_ahead;
uint8_t stripe_sz;
uint8_t status;
uint8_t write_mode;
uint8_t direct_io;
uint8_t row_size;
} __attribute__ ((packed)) logdrv_param_t;
/**
* logdrv_40ld_t - logical drive definition for 40LD controllers
* @lparam : logical drives parameters
* @span : span
*/
typedef struct {
logdrv_param_t lparam;
adap_span_40ld_t span[SPAN_DEPTH_8_SPANS];
}__attribute__ ((packed)) logdrv_40ld_t;
/**
* logdrv_8ld_span8_t - logical drive definition for 8LD controllers
* @lparam : logical drives parameters
* @span : span
*
* 8-LD logical drive with upto 8 spans
*/
typedef struct {
logdrv_param_t lparam;
adap_span_8ld_t span[SPAN_DEPTH_8_SPANS];
}__attribute__ ((packed)) logdrv_8ld_span8_t;
/**
* logdrv_8ld_span4_t - logical drive definition for 8LD controllers
* @lparam : logical drives parameters
* @span : span
*
* 8-LD logical drive with upto 4 spans
*/
typedef struct {
logdrv_param_t lparam;
adap_span_8ld_t span[SPAN_DEPTH_4_SPANS];
}__attribute__ ((packed)) logdrv_8ld_span4_t;
/**
* phys_drive_t - physical device information
* @type : Type of the device
* @cur_status : current status of the device
* @tag_depth : Level of tagging
* @sync_neg : sync negotiation - ENABLE or DISBALE
* @size : configurable size in terms of 512 byte
*/
typedef struct {
uint8_t type;
uint8_t cur_status;
uint8_t tag_depth;
uint8_t sync_neg;
uint32_t size;
}__attribute__ ((packed)) phys_drive_t;
/**
* disk_array_40ld_t - disk array for 40LD controllers
* @numldrv : number of logical drives
* @resvd :
* @ldrv : logical drives information
* @pdrv : physical drives information
*/
typedef struct {
uint8_t numldrv;
uint8_t resvd[3];
logdrv_40ld_t ldrv[MAX_LOGICAL_DRIVES_40LD];
phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES];
}__attribute__ ((packed)) disk_array_40ld_t;
/**
* disk_array_8ld_span8_t - disk array for 8LD controllers
* @numldrv : number of logical drives
* @resvd :
* @ldrv : logical drives information
* @pdrv : physical drives information
*
* Disk array for 8LD logical drives with upto 8 spans
*/
typedef struct {
uint8_t numldrv;
uint8_t resvd[3];
logdrv_8ld_span8_t ldrv[MAX_LOGICAL_DRIVES_8LD];
phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES];
}__attribute__ ((packed)) disk_array_8ld_span8_t;
/**
* disk_array_8ld_span4_t - disk array for 8LD controllers
* @numldrv : number of logical drives
* @resvd :
* @ldrv : logical drives information
* @pdrv : physical drives information
*
* Disk array for 8LD logical drives with upto 4 spans
*/
typedef struct {
uint8_t numldrv;
uint8_t resvd[3];
logdrv_8ld_span4_t ldrv[MAX_LOGICAL_DRIVES_8LD];
phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES];
}__attribute__ ((packed)) disk_array_8ld_span4_t;
/**
* private_bios_data - bios private data for boot devices
* @geometry : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB,
* 0x1000 - 8GB, Others values are invalid
* @unused : bits 4-7 are unused
* @boot_drv : logical drive set as boot drive, 0..7 - for 8LD cards,
* 0..39 - for 40LD cards
* @cksum : 0-(sum of first 13 bytes of this structure)
*/
struct private_bios_data {
uint8_t geometry :4;
uint8_t unused :4;
uint8_t boot_drv;
uint8_t rsvd[12];
uint16_t cksum;
} __attribute__ ((packed));
/**
* mbox_sgl64 - 64-bit scatter list for mailbox based controllers
* @address : address of the buffer
* @length : data transfer length
*/
typedef struct {
uint64_t address;
uint32_t length;
} __attribute__ ((packed)) mbox_sgl64;
/**
* mbox_sgl32 - 32-bit scatter list for mailbox based controllers
* @address : address of the buffer
* @length : data transfer length
*/
typedef struct {
uint32_t address;
uint32_t length;
} __attribute__ ((packed)) mbox_sgl32;
#endif // _MRAID_MBOX_DEFS_H_
/* vim: set ts=8 sw=8 tw=78: */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : mega_common.h
*
* Libaray of common routine used by all low-level megaraid drivers
*/
#ifndef _MEGA_COMMON_H_
#define _MEGA_COMMON_H_
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/list.h>
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <asm/semaphore.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#define LSI_MAX_CHANNELS 16
#define LSI_MAX_LOGICAL_DRIVES_64LD (64+1)
/**
* scb_t - scsi command control block
* @param ccb : command control block for individual driver
* @param list : list of control blocks
* @param gp : general purpose field for LLDs
* @param sno : all SCBs have a serial number
* @param scp : associated scsi command
* @param state : current state of scb
* @param dma_dir : direction of data transfer
* @param dma_type : transfer with sg list, buffer, or no data transfer
* @param dev_channel : actual channel on the device
* @param dev_target : actual target on the device
* @param status : completion status
*
* This is our central data structure to issue commands the each driver.
* Driver specific data structures are maintained in the ccb field.
* scb provides a field 'gp', which can be used by LLD for its own purposes
*
* dev_channel and dev_target must be initialized with the actual channel and
* target on the controller.
*/
typedef struct {
caddr_t ccb;
struct list_head list;
unsigned long gp;
unsigned int sno;
struct scsi_cmnd *scp;
uint32_t state;
uint32_t dma_direction;
uint32_t dma_type;
uint16_t dev_channel;
uint16_t dev_target;
uint32_t status;
} scb_t;
/*
* SCB states as it transitions from one state to another
*/
#define SCB_FREE 0x0000 /* on the free list */
#define SCB_ACTIVE 0x0001 /* off the free list */
#define SCB_PENDQ 0x0002 /* on the pending queue */
#define SCB_ISSUED 0x0004 /* issued - owner f/w */
#define SCB_ABORT 0x0008 /* Got an abort for this one */
#define SCB_RESET 0x0010 /* Got a reset for this one */
/*
* DMA types for scb
*/
#define MRAID_DMA_NONE 0x0000 /* no data transfer for this command */
#define MRAID_DMA_WSG 0x0001 /* data transfer using a sg list */
#define MRAID_DMA_WBUF 0x0002 /* data transfer using a contiguous buffer */
/**
* struct adapter_t - driver's initialization structure
* @param dpc_h : tasklet handle
* @param pdev : pci configuration pointer for kernel
* @param host : pointer to host structure of mid-layer
* @param host_lock : pointer to appropriate lock
* @param lock : synchronization lock for mid-layer and driver
* @param quiescent : driver is quiescent for now.
* @param outstanding_cmds : number of commands pending in the driver
* @param kscb_list : pointer to the bulk of SCBs pointers for IO
* @param kscb_pool : pool of free scbs for IO
* @param kscb_pool_lock : lock for pool of free scbs
* @param pend_list : pending commands list
* @param pend_list_lock : exlusion lock for pending commands list
* @param completed_list : list of completed commands
* @param completed_list_lock : exclusion lock for list of completed commands
* @param sglen : max sg elements supported
* @param device_ids : to convert kernel device addr to our devices.
* @param raid_device : raid adapter specific pointer
* @param max_channel : maximum channel number supported - inclusive
* @param max_target : max target supported - inclusive
* @param max_lun : max lun supported - inclusive
* @param list : list of megaraid host structures
* @param unique_id : unique identifier for each adapter
* @param irq : IRQ for this adapter
* @param ito : internal timeout value, (-1) means no timeout
* @param ibuf : buffer to issue internal commands
* @param ibuf_dma_h : dma handle for the above buffer
* @param uscb_list : SCB pointers for user cmds, common mgmt module
* @param uscb_pool : pool of SCBs for user commands
* @param uscb_pool_lock : exclusion lock for these SCBs
* @param max_cmds : max outstanding commands
* @param fw_version : firmware version
* @param bios_version : bios version
* @param max_cdb_sz : biggest CDB size supported.
* @param ha : is high availability present - clustering
* @param init_id : initiator ID, the default value should be 7
* @param max_sectors : max sectors per request
* @param cmd_per_lun : max outstanding commands per LUN
* @param being_detached : set when unloading, no more mgmt calls
*
*
* mraid_setup_device_map() can be called anytime after the device map is
* available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is
* required, usually from LLD's queue entry point. The formar API sets up the
* MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the
* device in question is a logical drive.
*
* quiescent flag should be set by the driver if it is not accepting more
* commands
*
* NOTE: The fields of this structures are placed to minimize cache misses
*/
// amount of space required to store the bios and firmware version strings
#define VERSION_SIZE 16
typedef struct {
struct tasklet_struct dpc_h;
struct pci_dev *pdev;
struct Scsi_Host *host;
spinlock_t *host_lock;
spinlock_t lock;
uint8_t quiescent;
int outstanding_cmds;
scb_t *kscb_list;
struct list_head kscb_pool;
spinlock_t kscb_pool_lock;
struct list_head pend_list;
spinlock_t pend_list_lock;
struct list_head completed_list;
spinlock_t completed_list_lock;
uint16_t sglen;
int device_ids[LSI_MAX_CHANNELS]
[LSI_MAX_LOGICAL_DRIVES_64LD];
caddr_t raid_device;
uint8_t max_channel;
uint16_t max_target;
uint8_t max_lun;
struct list_head list;
uint32_t unique_id;
uint8_t irq;
uint8_t ito;
caddr_t ibuf;
dma_addr_t ibuf_dma_h;
scb_t *uscb_list;
struct list_head uscb_pool;
spinlock_t uscb_pool_lock;
int max_cmds;
uint8_t fw_version[VERSION_SIZE];
uint8_t bios_version[VERSION_SIZE];
uint8_t max_cdb_sz;
uint8_t ha;
uint16_t init_id;
uint16_t max_sectors;
uint16_t cmd_per_lun;
atomic_t being_detached;
} adapter_t;
#define SCSI_FREE_LIST_LOCK(adapter) (&adapter->kscb_pool_lock)
#define USER_FREE_LIST_LOCK(adapter) (&adapter->uscb_pool_lock)
#define PENDING_LIST_LOCK(adapter) (&adapter->pend_list_lock)
#define COMPLETED_LIST_LOCK(adapter) (&adapter->completed_list_lock)
// conversion from scsi command
#define SCP2HOST(scp) (scp)->device->host // to host
#define SCP2HOSTDATA(scp) SCP2HOST(scp)->hostdata // to soft state
#define SCP2CHANNEL(scp) (scp)->device->channel // to channel
#define SCP2TARGET(scp) (scp)->device->id // to target
#define SCP2LUN(scp) (scp)->device->lun // to LUN
// generic macro to convert scsi command and host to controller's soft state
#define SCSIHOST2ADAP(host) (((caddr_t *)(host->hostdata))[0])
#define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp))
/**
* MRAID_GET_DEVICE_MAP - device ids
* @param adp - Adapter's soft state
* @param scp - mid-layer scsi command pointer
* @param p_chan - physical channel on the controller
* @param target - target id of the device or logical drive number
* @param islogical - set if the command is for the logical drive
*
* Macro to retrieve information about device class, logical or physical and
* the corresponding physical channel and target or logical drive number
**/
#define MRAID_IS_LOGICAL(adp, scp) \
(SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0
#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \
/* \
* Is the request coming for the virtual channel \
*/ \
islogical = MRAID_IS_LOGICAL(adp, scp); \
\
/* \
* Get an index into our table of drive ids mapping \
*/ \
if (islogical) { \
p_chan = 0xFF; \
target = \
(adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)]; \
} \
else { \
p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)] \
[SCP2TARGET(scp)] >> 8) & 0xFF; \
target = ((adp)->device_ids[SCP2CHANNEL(scp)] \
[SCP2TARGET(scp)] & 0xFF); \
}
/**
* struct mraid_driver_t - global driver data
* @param driver_version : driver version
* @param device_list : list of adapter_t structures
*
* mraid_driver_t contains information which is global to the driver.
*/
typedef struct {
uint8_t driver_version[8];
struct list_head device_list;
} mraid_driver_t;
/*
* ### Helper routines ###
*/
#define LSI_DBGLVL mraid_debug_level // each LLD must define a global
// mraid_debug_level
#ifdef DEBUG
#if defined (_ASSERT_PANIC)
#define ASSERT_ACTION panic
#else
#define ASSERT_ACTION printk
#endif
#define ASSERT(expression) \
if (!(expression)) { \
ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \
#expression, __FILE__, __LINE__, __FUNCTION__); \
}
#else
#define ASSERT(expression)
#endif
/*
* struct mraid_pci_blk - structure holds DMA memory block info
* @param vaddr : virtual address to a memory block
* @param dma_addr : DMA handle to a memory block
*
* This structure is filled up for the caller. It is the responsibilty of the
* caller to allocate this array big enough to store addresses for all
* requested elements
*/
struct mraid_pci_blk {
caddr_t vaddr;
dma_addr_t dma_addr;
};
#endif // _MEGA_COMMON_H_
// vim: set ts=8 sw=8 tw=78:
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_ioctl.h
*
* Definitions to interface with user level applications
*/
#ifndef _MEGARAID_IOCTL_H_
#define _MEGARAID_IOCTL_H_
#include <linux/types.h>
#include <asm/semaphore.h>
#include "mbox_defs.h"
/**
* con_log() - console log routine
* @param level : indicates the severity of the message.
* @fparam mt : format string
*
* con_log displays the error messages on the console based on the current
* debug level. Also it attaches the appropriate kernel severity level with
* the message.
*
*
* consolge messages debug levels
*/
#define CL_ANN 0 /* print unconditionally, announcements */
#define CL_DLEVEL1 1 /* debug level 1, informative */
#define CL_DLEVEL2 2 /* debug level 2, verbose */
#define CL_DLEVEL3 3 /* debug level 3, very verbose */
#define con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt;
/*
* Definitions & Declarations needed to use common management module
*/
#define MEGAIOC_MAGIC 'm'
#define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0, mimd_t)
#define MEGAIOC_QNADAP 'm' /* Query # of adapters */
#define MEGAIOC_QDRVRVER 'e' /* Query driver version */
#define MEGAIOC_QADAPINFO 'g' /* Query adapter information */
#define USCSICMD 0x80
#define UIOC_RD 0x00001
#define UIOC_WR 0x00002
#define MBOX_CMD 0x00000
#define GET_DRIVER_VER 0x10000
#define GET_N_ADAP 0x20000
#define GET_ADAP_INFO 0x30000
#define GET_CAP 0x40000
#define GET_STATS 0x50000
#define GET_IOCTL_VERSION 0x01
#define MAX_LSI_CMN_ADAPS 16
#define EXT_IOCTL_SIGN_SZ 16
#define EXT_IOCTL_SIGN "$$_EXTD_IOCTL_$$"
#define MBOX_LEGACY 0x00 /* ioctl has legacy mbox*/
#define MBOX_HPE 0x01 /* ioctl has hpe mbox */
#define APPTYPE_MIMD 0x00 /* old existing apps */
#define APPTYPE_UIOC 0x01 /* new apps using uioc */
#define IOCTL_ISSUE 0x00000001 /* Issue ioctl */
#define IOCTL_ABORT 0x00000002 /* Abort previous ioctl */
#define DRVRTYPE_MBOX 0x00000001 /* regular mbox driver */
#define DRVRTYPE_HPE 0x00000002 /* new hpe driver */
#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) )
#define GETADAP(mkadap) ((mkadap) ^ MEGAIOC_MAGIC << 8)
#define MAX_DMA_POOLS 5 /* 4k, 8k, 16k, 32k, 64k*/
/**
* struct uioc_t - the common ioctl packet structure
*
* @signature : Must be "$$_EXTD_IOCTL_$$"
* @mb_type : Type of the mail box (MB_LEGACY or MB_HPE)
* @app_type : Type of the issuing application (existing or new)
* @opcode : Opcode of the command
* @adapno : Adapter number
* @cmdbuf : Pointer to buffer - can point to mbox or plain data buffer
* @xferlen : xferlen for DCMD and non mailbox commands
* @data_dir : Direction of the data transfer
* @status : Status from the driver
* @reserved : reserved bytes for future expansion
*
* @user_data : user data transfer address is saved in this
* @user_data_len: length of the data buffer sent by user app
* @user_pthru : user passthru address is saves in this (null if DCMD)
* @pthru32 : kernel address passthru (allocated per kioc)
* @pthru32_h : physicall address of @pthru32
* @list : for kioc free pool list maintenance
* @done : call back routine for llds to call when kioc is completed
* @buf_vaddr : dma pool buffer attached to kioc for data transfer
* @buf_paddr : physical address of the dma pool buffer
* @pool_index : index of the dma pool that @buf_vaddr is taken from
* @free_buf : indicates if buffer needs to be freed after kioc completes
*
* Note : All LSI drivers understand only this packet. Any other
* : format sent by applications would be converted to this.
*/
typedef struct uioc {
/* User Apps: */
uint8_t signature[EXT_IOCTL_SIGN_SZ];
uint16_t mb_type;
uint16_t app_type;
uint32_t opcode;
uint32_t adapno;
uint64_t cmdbuf;
uint32_t xferlen;
uint32_t data_dir;
int32_t status;
uint8_t reserved[128];
/* Driver Data: */
caddr_t user_data;
uint32_t user_data_len;
mraid_passthru_t *user_pthru;
mraid_passthru_t *pthru32;
dma_addr_t pthru32_h;
struct list_head list;
void (*done)(struct uioc*);
caddr_t buf_vaddr;
dma_addr_t buf_paddr;
uint8_t pool_index;
uint8_t free_buf;
} __attribute__ ((aligned(1024),packed)) uioc_t;
/**
* struct mraid_hba_info - information about the controller
*
* @param pci_vendor_id : PCI vendor id
* @param pci_device_id : PCI device id
* @param subsystem_vendor_id : PCI subsystem vendor id
* @param subsystem_device_id : PCI subsystem device id
* @param baseport : base port of hba memory
* @param pci_bus : PCI bus
* @param pci_dev_fn : PCI device/function values
* @param irq : interrupt vector for the device
*
* Extended information of 256 bytes about the controller. Align on the single
* byte boundary so that 32-bit applications can be run on 64-bit platform
* drivers withoug re-compilation.
* NOTE: reduce the number of reserved bytes whenever new field are added, so
* that total size of the structure remains 256 bytes.
*/
typedef struct mraid_hba_info {
uint16_t pci_vendor_id;
uint16_t pci_device_id;
uint16_t subsys_vendor_id;
uint16_t subsys_device_id;
uint64_t baseport;
uint8_t pci_bus;
uint8_t pci_dev_fn;
uint8_t pci_slot;
uint8_t irq;
uint32_t unique_id;
uint32_t host_no;
uint8_t num_ldrv;
} __attribute__ ((aligned(256), packed)) mraid_hba_info_t;
/**
* mcontroller : adapter info structure for old mimd_t apps
*
* @base : base address
* @irq : irq number
* @numldrv : number of logical drives
* @pcibus : pci bus
* @pcidev : pci device
* @pcifun : pci function
* @pciid : pci id
* @pcivendor : vendor id
* @pcislot : slot number
* @uid : unique id
*/
typedef struct mcontroller {
uint64_t base;
uint8_t irq;
uint8_t numldrv;
uint8_t pcibus;
uint16_t pcidev;
uint8_t pcifun;
uint16_t pciid;
uint16_t pcivendor;
uint8_t pcislot;
uint32_t uid;
} __attribute__ ((packed)) mcontroller_t;
/**
* mm_dmapool_t : Represents one dma pool with just one buffer
*
* @vaddr : Virtual address
* @paddr : DMA physicall address
* @bufsize : In KB - 4 = 4k, 8 = 8k etc.
* @handle : Handle to the dma pool
* @lock : lock to synchronize access to the pool
* @in_use : If pool already in use, attach new block
*/
typedef struct mm_dmapool {
caddr_t vaddr;
dma_addr_t paddr;
uint32_t buf_size;
struct dma_pool *handle;
spinlock_t lock;
uint8_t in_use;
} mm_dmapool_t;
/**
* mraid_mmadp_t: Structure that drivers pass during (un)registration
*
* @unique_id : Any unique id (usually PCI bus+dev+fn)
* @drvr_type : megaraid or hpe (DRVRTYPE_MBOX or DRVRTYPE_HPE)
* @drv_data : Driver specific; not touched by the common module
* @timeout : timeout for issued kiocs
* @max_kioc : Maximum ioctl packets acceptable by the lld
* @pdev : pci dev; used for allocating dma'ble memory
* @issue_uioc : Driver supplied routine to issue uioc_t commands
* : issue_uioc(drvr_data, kioc, ISSUE/ABORT, uioc_done)
* @kioc_list : block of mem for @max_kioc number of kiocs
* @kioc_pool : pool of free kiocs
* @kioc_pool_lock : protection for free pool
* @kioc_semaphore : so as not to exceed @max_kioc parallel ioctls
* @mbox_list : block of mem for @max_kioc number of mboxes
* @pthru_dma_pool : DMA pool to allocate passthru packets
* @dma_pool_list : array of dma pools
*/
typedef struct mraid_mmadp {
/* Filled by driver */
uint32_t unique_id;
uint32_t drvr_type;
unsigned long drvr_data;
uint8_t timeout;
uint8_t max_kioc;
struct pci_dev *pdev;
int(*issue_uioc)(unsigned long, uioc_t *, uint32_t);
/* Maintained by common module */
uioc_t *kioc_list;
struct list_head kioc_pool;
spinlock_t kioc_pool_lock;
struct semaphore kioc_semaphore;
mbox64_t *mbox_list;
struct dma_pool *pthru_dma_pool;
mm_dmapool_t dma_pool_list[MAX_DMA_POOLS];
} mraid_mmadp_t;
int mraid_mm_register_adp(mraid_mmadp_t *);
int mraid_mm_unregister_adp(uint32_t);
#endif /* _MEGARAID_IOCTL_H_ */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid.c
* Version : v2.20.0.0 (June 23 2004)
*
* Authors:
* Atul Mukker <Atul.Mukker@lsil.com>
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
* Manoj Jose <Manoj.Jose@lsil.com>
*
* List of supported controllers
*
* OEM Product Name VID DID SSVID SSID
* --- ------------ --- --- ---- ----
* Dell PERC3/QC 101E 1960 1028 0471
* Dell PERC3/DC 101E 1960 1028 0493
* Dell PERC3/SC 101E 1960 1028 0475
* Dell PERC3/Di 1028 1960 1028 0123
* Dell PERC4/SC 1000 1960 1028 0520
* Dell PERC4/DC 1000 1960 1028 0518
* Dell PERC4/QC 1000 0407 1028 0531
* Dell PERC4/Di 1028 000F 1028 014A
* Dell PERC 4e/Si 1028 0013 1028 016c
* Dell PERC 4e/Di 1028 0013 1028 016d
* Dell PERC 4e/Di 1028 0013 1028 016e
* Dell PERC 4e/Di 1028 0013 1028 016f
* Dell PERC 4e/Di 1028 0013 1028 0170
* Dell PERC 4e/DC 1000 0408 1028 0002
* Dell PERC 4e/SC 1000 0408 1028 0001
*
*
* LSI MegaRAID SCSI 320-0 1000 1960 1000 A520
* LSI MegaRAID SCSI 320-1 1000 1960 1000 0520
* LSI MegaRAID SCSI 320-2 1000 1960 1000 0518
* LSI MegaRAID SCSI 320-0X 1000 0407 1000 0530
* LSI MegaRAID SCSI 320-2X 1000 0407 1000 0532
* LSI MegaRAID SCSI 320-4X 1000 0407 1000 0531
* LSI MegaRAID SCSI 320-1E 1000 0408 1000 0001
* LSI MegaRAID SCSI 320-2E 1000 0408 1000 0002
* LSI MegaRAID SATA 150-2 1095 3112 1000 0534
* LSI MegaRAID SATA 150-4 1000 1960 1000 4523
* LSI MegaRAID SATA 150-6 1000 1960 1000 0523
* LSI MegaRAID SATA 150-4X 1000 0409 1000 1504
* LSI MegaRAID SATA 150-8X 1000 0409 1000 1508
*
* INTEL RAID Controller SRCU42X 1000 0407 8086 0532
* INTEL RAID Controller SRCS16 1000 1960 8086 0523
* INTEL RAID Controller SRCU42E 1000 0408 8086 0002
* INTEL RAID Controller SRCZCRX 1000 0407 8086 0530
* INTEL RAID Controller SRCS28X 1000 0409 8086 3008
* INTEL RAID Controller SROMBU42E 1000 0408 8086 3431
* INTEL RAID Controller SROMBU42E 1000 0408 8086 3499
* INTEL RAID Controller SRCU51L 1000 1960 8086 0520
*
*
* FSC MegaRAID PCI Express ROMB 1000 0408 1734 1065
*
*
* For history of changes, see changelog.megaraid
*/
#include "megaraid_mbox.h"
static int megaraid_init(void);
static void megaraid_exit(void);
static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *);
static void megaraid_detach_one(struct pci_dev *);
static void megaraid_mbox_shutdown(struct device *);
static int megaraid_io_attach(adapter_t *);
static void megaraid_io_detach(adapter_t *);
static int megaraid_alloc_cmd_packets(adapter_t *);
static void megaraid_free_cmd_packets(adapter_t *);
static int megaraid_mbox_setup_dma_pools(adapter_t *);
static void megaraid_mbox_teardown_dma_pools(adapter_t *);
static int megaraid_init_mbox(adapter_t *);
static void megaraid_fini_mbox(adapter_t *);
static int megaraid_abort_handler(struct scsi_cmnd *);
static int megaraid_reset_handler(struct scsi_cmnd *);
static int mbox_post_sync_cmd(adapter_t *, uint8_t []);
static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []);
static int megaraid_mbox_product_info(adapter_t *);
static int megaraid_mbox_extended_cdb(adapter_t *);
static int megaraid_mbox_support_random_del(adapter_t *);
static int megaraid_mbox_support_ha(adapter_t *, uint16_t *);
static int megaraid_mbox_get_max_sg(adapter_t *);
static void megaraid_mbox_enum_raid_scsi(adapter_t *);
static void megaraid_mbox_flush_cache(adapter_t *);
static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
static void megaraid_mbox_setup_device_map(adapter_t *);
static int megaraid_queue_command(struct scsi_cmnd *,
void (*)(struct scsi_cmnd *));
static inline scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *,
int *);
static inline scb_t *megaraid_alloc_scb(adapter_t *, struct scsi_cmnd *);
static inline void megaraid_dealloc_scb(adapter_t *, scb_t *);
static inline void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
struct scsi_cmnd *);
static inline void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
struct scsi_cmnd *);
static inline int megaraid_mbox_mksgl(adapter_t *, scb_t *);
static inline void megaraid_mbox_runpendq(adapter_t *, scb_t *);
static inline int mbox_post_cmd(adapter_t *, scb_t *);
static void megaraid_mbox_dpc(unsigned long);
static inline void megaraid_mbox_sync_scb(adapter_t *, scb_t *);
static irqreturn_t megaraid_isr(int, void *, struct pt_regs *);
static inline int megaraid_ack_sequence(adapter_t *);
static inline int megaraid_busywait_mbox(mraid_device_t *);
static inline int __megaraid_busywait_mbox(mraid_device_t *);
static int megaraid_cmm_register(adapter_t *);
static int megaraid_cmm_unregister(adapter_t *);
static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t);
static int megaraid_mbox_mm_command(adapter_t *, uioc_t *);
static void megaraid_mbox_mm_done(adapter_t *, scb_t *);
static int gather_hbainfo(adapter_t *, mraid_hba_info_t *);
static int wait_till_fw_empty(adapter_t *);
MODULE_AUTHOR("LSI Logic Corporation");
MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGARAID_VERSION);
/*
* ### modules parameters for driver ###
*/
/**
* Set to enable driver to expose unconfigured disk to kernel
*/
static int megaraid_expose_unconf_disks = 0;
module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0);
MODULE_PARM_DESC(unconf_disks,
"Set to expose unconfigured disks to kernel (default=0)");
/**
* driver wait time if the adapter's mailbox is busy
*/
static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT;
module_param_named(busy_wait, max_mbox_busy_wait, int, 0);
MODULE_PARM_DESC(busy_wait,
"Max wait for mailbox in microseconds if busy (default=10)");
/**
* number of sectors per IO command
*/
static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS;
module_param_named(max_sectors, megaraid_max_sectors, int, 0);
MODULE_PARM_DESC(max_sectors,
"Maximum number of sectors per IO command (default=128)");
/**
* number of commands per logical unit
*/
static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN;
module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0);
MODULE_PARM_DESC(cmd_per_lun,
"Maximum number of commands per logical unit (default=64)");
/**
* Fast driver load option, skip scanning for physical devices during load.
* This would result in non-disk devices being skipped during driver load
* time. These can be later added though, using /proc/scsi/scsi
*/
static unsigned int megaraid_fast_load = 0;
module_param_named(fast_load, megaraid_fast_load, int, 0);
MODULE_PARM_DESC(fast_load,
"Faster loading of the driver, skips physical devices! (default=0)");
/**
* mraid_debug level - threshold for amount of information to be displayed by
* the driver. This level can be changed through modules parameters, ioctl or
* sysfs/proc interface. By default, print the announcement messages only.
*/
int mraid_debug_level = CL_ANN;
module_param_named(debug_level, mraid_debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)");
/*
* ### global data ###
*/
mraid_driver_t mraid_driver_g = {
.driver_version = { 0x02, 0x20, 0x00, 0x00, 6, 21, 20, 4},
};
/*
* PCI table for all supported controllers.
*/
static struct pci_device_id pci_id_table_g[] = {
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4_DI_DISCOVERY,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4_DI_DISCOVERY,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_PERC4_SC,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4_SC,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_PERC4_DC,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4_DC,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_PERC4_QC,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4_QC,
},
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4_DI_EVERGLADES,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4_DI_EVERGLADES,
},
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4E_SI_BIGBEND,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_SI_BIGBEND,
},
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4E_DI_KOBUK,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_DI_KOBUK,
},
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4E_DI_CORVETTE,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_DI_CORVETTE,
},
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4E_DI_EXPEDITION,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION,
},
{
PCI_VENDOR_ID_DELL,
PCI_DEVICE_ID_PERC4E_DI_GUADALUPE,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_PERC4E_DC_320_2E,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_DC_320_2E,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_PERC4E_SC_320_1E,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC4E_SC_320_1E,
},
{
PCI_VENDOR_ID_AMI,
PCI_DEVICE_ID_AMI_MEGARAID3,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC3_QC,
},
{
PCI_VENDOR_ID_AMI,
PCI_DEVICE_ID_AMI_MEGARAID3,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC3_DC,
},
{
PCI_VENDOR_ID_AMI,
PCI_DEVICE_ID_AMI_MEGARAID3,
PCI_VENDOR_ID_DELL,
PCI_SUBSYS_ID_PERC3_SC,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_0,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_0,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_1,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_1,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_2,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_2,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_0x,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_2x,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_4x,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_1E,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SCSI_320_2E,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SATA_150_4,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SATA_150_4,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SATA_150_6,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SATA_150_6,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SATA_300_4x,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SATA_300_4x,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_MEGARAID_SATA_300_8x,
PCI_VENDOR_ID_LSI_LOGIC,
PCI_SUBSYS_ID_MEGARAID_SATA_300_8x,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SRCU42X,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SRCU42X,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SRCS16,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SRCS16,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SRCU42E,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SRCU42E,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SRCZCRX,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SRCS28X,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SRCS28X,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
PCI_VENDOR_ID_INTEL,
PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
},
{
PCI_VENDOR_ID_LSI_LOGIC,
PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB,
PCI_SUBSYS_ID_FSC,
PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB,
},
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, pci_id_table_g);
static struct pci_driver megaraid_pci_driver_g = {
.name = "megaraid",
.id_table = pci_id_table_g,
.probe = megaraid_probe_one,
.remove = __devexit_p(megaraid_detach_one),
.driver = {
.shutdown = megaraid_mbox_shutdown,
}
};
/*
* Scsi host template for megaraid unified driver
*/
static struct scsi_host_template megaraid_template_g = {
.module = THIS_MODULE,
.name = "LSI Logic MegaRAID driver",
.proc_name = "megaraid",
.queuecommand = megaraid_queue_command,
.eh_abort_handler = megaraid_abort_handler,
.eh_device_reset_handler = megaraid_reset_handler,
.eh_bus_reset_handler = megaraid_reset_handler,
.eh_host_reset_handler = megaraid_reset_handler,
.use_clustering = ENABLE_CLUSTERING,
};
/**
* megaraid_init - module load hook
*
* We register ourselves as hotplug enabled module and let PCI subsystem
* discover our adaters
**/
static int __init
megaraid_init(void)
{
int rval;
// Announce the driver version
con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION,
MEGARAID_EXT_VERSION));
// check validity of module parameters
if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: max commands per lun reset to %d\n",
MBOX_MAX_SCSI_CMDS));
megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS;
}
/*
* Setup the driver global data structures
*/
INIT_LIST_HEAD(&mraid_driver_g.device_list);
// register as a PCI hot-plug driver module
if ((rval = pci_module_init(&megaraid_pci_driver_g))) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: could not register hotplug support.\n"));
}
return rval;
}
/**
* megaraid_exit - driver unload entry point
*
* We simply unwrap the megaraid_init routine here
*/
static void __exit
megaraid_exit(void)
{
con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
// unregister as PCI hotplug driver
pci_unregister_driver(&megaraid_pci_driver_g);
// All adapters must be detached by now
ASSERT(list_empty(&mraid_driver_g.device_list));
return;
}
/**
* megaraid_probe_one - PCI hotplug entry point
* @param pdev : handle to this controller's PCI configuration space
* @param id : pci device id of the class of controllers
*
* This routine should be called whenever a new adapter is detected by the
* PCI hotplug susbsytem.
**/
static int __devinit
megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
adapter_t *adapter;
uint8_t alloc_adapter_f = 0;
uint8_t init_mbox_f = 0;
uint8_t cmm_reg_f = 0;
uint8_t io_attach_f = 0;
// detected a new controller
con_log(CL_ANN, (KERN_INFO
"megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device));
con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)));
if (pci_enable_device(pdev)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: pci_enable_device failed\n"));
return -ENODEV;
}
// Enable bus-mastering on this controller
pci_set_master(pdev);
// Allocate the per driver initialization structure
adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
if (adapter == NULL) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__));
goto fail_probe_one;
}
alloc_adapter_f = 1;
memset(adapter, 0, sizeof(adapter_t));
// set up PCI related soft state and other pre-known parameters
adapter->unique_id = pdev->bus->number << 8 | pdev->devfn;
adapter->irq = pdev->irq;
adapter->pdev = pdev;
atomic_set(&adapter->being_detached, 0);
// Setup the default DMA mask. This would be changed later on
// depending on hardware capabilities
if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFF) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: pci_set_dma_mask failed:%d\n", __LINE__));
goto fail_probe_one;
}
// Initialize the synchronization lock for kernel and LLD
spin_lock_init(&adapter->lock);
adapter->host_lock = &adapter->lock;
// Initialize the command queues: the list of free SCBs and the list
// of pending SCBs.
INIT_LIST_HEAD(&adapter->kscb_pool);
spin_lock_init(SCSI_FREE_LIST_LOCK(adapter));
INIT_LIST_HEAD(&adapter->pend_list);
spin_lock_init(PENDING_LIST_LOCK(adapter));
INIT_LIST_HEAD(&adapter->completed_list);
spin_lock_init(COMPLETED_LIST_LOCK(adapter));
// Start the mailbox based controller
if (megaraid_init_mbox(adapter) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: maibox adapter did not initialize\n"));
goto fail_probe_one;
}
init_mbox_f = 1;
// Register with LSI Common Management Module
if (megaraid_cmm_register(adapter) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: could not register with management module\n"));
goto fail_probe_one;
}
cmm_reg_f = 1;
// setup adapter handle in PCI soft state
pci_set_drvdata(pdev, adapter);
// attach with scsi mid-layer
if (megaraid_io_attach(adapter) != 0) {
con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n"));
goto fail_probe_one;
}
io_attach_f = 1;
// Adapter setup complete, put it in the global list of controllers
list_add_tail(&adapter->list, &mraid_driver_g.device_list);
return 0;
fail_probe_one:
if (io_attach_f) {
megaraid_io_detach(adapter);
pci_set_drvdata(pdev, NULL);
}
if (cmm_reg_f) {
megaraid_cmm_unregister(adapter);
}
if (init_mbox_f) {
megaraid_fini_mbox(adapter);
}
if (alloc_adapter_f) {
kfree(adapter);
}
pci_disable_device(pdev);
return -ENODEV;
}
/**
* megaraid_detach_one - release the framework resources and call LLD release
* routine
* @param pdev : handle for our PCI cofiguration space
*
* This routine is called during driver unload. We free all the allocated
* resources and call the corresponding LLD so that it can also release all
* its resources.
*
* This routine is also called from the PCI hotplug system
**/
static void
megaraid_detach_one(struct pci_dev *pdev)
{
adapter_t *adapter;
// Start a rollback on this adapter
adapter = pci_get_drvdata(pdev);
if (!adapter) {
con_log(CL_ANN, (KERN_CRIT
"megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device));
return;
}
else {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device));
}
// do not allow any more requests from the management module for this
// adapter.
// FIXME: How do we account for the request which might still be
// pending with us?
atomic_set(&adapter->being_detached, 1);
// remove the adapter from the global list of our controllers
list_del_init(&adapter->list);
// detach from the IO sub-system
megaraid_io_detach(adapter);
// reset the device state in the PCI structure. We check this
// condition when we enter here. If the device state is NULL,
// that would mean the device has already been removed
pci_set_drvdata(pdev, NULL);
// Unregister from common management module
//
// FIXME: this must return success or failure for conditions if there
// is a command pending with LLD or not.
megaraid_cmm_unregister(adapter);
// finalize the mailbox based controller and release all resources
megaraid_fini_mbox(adapter);
kfree(adapter);
pci_disable_device(pdev);
return;
}
/**
* megaraid_mbox_shutdown - PCI shutdown for megaraid HBA
* @param device : generice driver model device
*
* Shutdown notification, perform flush cache
*/
static void
megaraid_mbox_shutdown(struct device *device)
{
adapter_t *adapter = pci_get_drvdata(to_pci_dev(device));
static int counter;
if (!adapter) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: null device in shutdown\n"));
return;
}
// flush caches now
con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...",
counter++));
megaraid_mbox_flush_cache(adapter);
con_log(CL_ANN, ("done\n"));
}
/**
* megaraid_io_attach - attach a device with the IO subsystem
* @param adapter : controller's soft state
*
* Attach this device with the IO subsystem
**/
static int
megaraid_io_attach(adapter_t *adapter)
{
struct Scsi_Host *host;
// Initialize SCSI Host structure
host = scsi_host_alloc(&megaraid_template_g, 8);
if (!host) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mbox: scsi_register failed\n"));
return -1;
}
SCSIHOST2ADAP(host) = (caddr_t )adapter;
adapter->host = host;
// export the parameters required by the mid-layer
scsi_assign_lock(host, adapter->host_lock);
scsi_set_device(host, &adapter->pdev->dev);
host->irq = adapter->irq;
host->unique_id = adapter->unique_id;
host->can_queue = adapter->max_cmds;
host->this_id = adapter->init_id;
host->sg_tablesize = adapter->sglen;
host->max_sectors = adapter->max_sectors;
host->cmd_per_lun = adapter->cmd_per_lun;
host->max_channel = adapter->max_channel;
host->max_id = adapter->max_target;
host->max_lun = adapter->max_lun;
// notify mid-layer about the new controller
if (scsi_add_host(host, &adapter->pdev->dev)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mbox: scsi_add_host failed\n"));
scsi_host_put(host);
return -1;
}
scsi_scan_host(host);
return 0;
}
/**
* megaraid_io_detach - detach a device from the IO subsystem
* @param adapter : controller's soft state
*
* Detach this device from the IO subsystem
**/
static void
megaraid_io_detach(adapter_t *adapter)
{
struct Scsi_Host *host;
con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n"));
host = adapter->host;
scsi_remove_host(host);
scsi_host_put(host);
return;
}
/*
* START: Mailbox Low Level Driver
*
* This is section specific to the single mailbox based controllers
*/
/**
* megaraid_init_mbox - initialize controller
* @param adapter - our soft state
*
* . Allocate 16-byte aligned mailbox memory for firmware handshake
* . Allocate controller's memory resources
* . Find out all initialization data
* . Allocate memory required for all the commands
* . Use internal library of FW routines, build up complete soft state
*/
static int __init
megaraid_init_mbox(adapter_t *adapter)
{
struct pci_dev *pdev;
mraid_device_t *raid_dev;
uint8_t mem_region_f = 0;
uint8_t alloc_cmds_f = 0;
uint8_t irq_f = 0;
int i;
adapter->ito = MBOX_TIMEOUT;
pdev = adapter->pdev;
/*
* Allocate and initialize the init data structure for mailbox
* controllers
*/
raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
if (raid_dev == NULL) return -1;
memset(raid_dev, 0, sizeof(mraid_device_t));
/*
* Attach the adapter soft state to raid device soft state
*/
adapter->raid_device = (caddr_t)raid_dev;
raid_dev->fast_load = megaraid_fast_load;
// our baseport
raid_dev->baseport = pci_resource_start(pdev, 0);
if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: mem region busy\n"));
goto fail_init;
}
raid_dev->baseaddr = (unsigned long)
ioremap_nocache(raid_dev->baseport, 128);
if (!raid_dev->baseaddr) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: could not map hba memory\n") );
pci_release_regions(pdev);
goto fail_init;
}
mem_region_f = 1;
//
// Setup the rest of the soft state using the library of FW routines
//
// request IRQ and register the interrupt service routine
if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid",
adapter)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n", adapter->irq));
goto fail_init;
}
irq_f = 1;
// initialize the mutual exclusion lock for the mailbox
spin_lock_init(&raid_dev->mailbox_lock);
// allocate memory required for commands
if (megaraid_alloc_cmd_packets(adapter) != 0) {
goto fail_init;
}
alloc_cmds_f = 1;
// Product info
if (megaraid_mbox_product_info(adapter) != 0) {
goto fail_init;
}
// Do we support extended CDBs
adapter->max_cdb_sz = 10;
if (megaraid_mbox_extended_cdb(adapter) == 0) {
adapter->max_cdb_sz = 16;
}
/*
* Do we support cluster environment, if we do, what is the initiator
* id.
* NOTE: In a non-cluster aware firmware environment, the LLD should
* return 7 as initiator id.
*/
adapter->ha = 0;
adapter->init_id = -1;
if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) {
adapter->ha = 1;
}
/*
* Prepare the device ids array to have the mapping between the kernel
* device address and megaraid device address.
* We export the physical devices on their actual addresses. The
* logical drives are exported on a virtual SCSI channel
*/
megaraid_mbox_setup_device_map(adapter);
// If the firmware supports random deletion, update the device id map
if (megaraid_mbox_support_random_del(adapter)) {
// Change the logical drives numbers in device_ids array one
// slot in device_ids is reserved for target id, that's why
// "<=" below
for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) {
adapter->device_ids[adapter->max_channel][i] += 0x80;
}
adapter->device_ids[adapter->max_channel][adapter->init_id] =
0xFF;
}
/*
* find out the maximum number of scatter-gather elements supported by
* this firmware
*/
adapter->sglen = megaraid_mbox_get_max_sg(adapter);
// enumerate RAID and SCSI channels so that all devices on SCSI
// channels can later be exported, including disk devices
megaraid_mbox_enum_raid_scsi(adapter);
/*
* Other parameters required by upper layer
*
* maximum number of sectors per IO command
*/
adapter->max_sectors = megaraid_max_sectors;
/*
* number of queued commands per LUN.
*/
adapter->cmd_per_lun = megaraid_cmd_per_lun;
// Set the DMA mask to 64-bit. All supported controllers as capable of
// DMA in this range
if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFFFFFFFFFFULL) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: could not set DMA mask for 64-bit.\n"));
goto fail_init;
}
// setup tasklet for DPC
tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc,
(unsigned long)adapter);
con_log(CL_DLEVEL1, (KERN_INFO
"megaraid mbox hba successfully initialized\n"));
return 0;
fail_init:
if (alloc_cmds_f) {
megaraid_free_cmd_packets(adapter);
}
if (irq_f) {
free_irq(adapter->irq, adapter);
}
if (mem_region_f) {
iounmap((caddr_t)raid_dev->baseaddr);
pci_release_regions(adapter->pdev);
}
kfree(raid_dev);
return -1;
}
/**
* megaraid_fini_mbox - undo controller initialization
* @param adapter : our soft state
*/
static void
megaraid_fini_mbox(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
// flush all caches
megaraid_mbox_flush_cache(adapter);
tasklet_kill(&adapter->dpc_h);
megaraid_free_cmd_packets(adapter);
free_irq(adapter->irq, adapter);
iounmap((caddr_t)raid_dev->baseaddr);
pci_release_regions(adapter->pdev);
kfree(raid_dev);
return;
}
/**
* megaraid_alloc_cmd_packets - allocate shared mailbox
* @param adapter : soft state of the raid controller
*
* Allocate and align the shared mailbox. This maibox is used to issue
* all the commands. For IO based controllers, the mailbox is also regsitered
* with the FW. Allocate memory for all commands as well.
* This is our big allocator
*/
static int
megaraid_alloc_cmd_packets(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
struct pci_dev *pdev;
unsigned long align;
scb_t *scb;
mbox_ccb_t *ccb;
struct mraid_pci_blk *epthru_pci_blk;
struct mraid_pci_blk *sg_pci_blk;
struct mraid_pci_blk *mbox_pci_blk;
uint8_t alloc_ibuf_f = 0;
uint8_t alloc_common_mbox_f = 0;
uint8_t alloc_scb_f = 0;
uint8_t dma_pools_f = 0;
int i;
pdev = adapter->pdev;
/*
* Setup the mailbox
* Allocate the common 16-byte aligned memory for the handshake
* mailbox.
*/
raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev,
sizeof(mbox64_t), &raid_dev->una_mbox64_dma);
if (!raid_dev->una_mbox64) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
return -1;
}
memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t));
alloc_common_mbox_f = 1;
/*
* Align the mailbox at 16-byte boundary
*/
raid_dev->mbox = &raid_dev->una_mbox64->mbox32;
raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) &
(~0UL ^ 0xFUL));
raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8);
align = ((void *)raid_dev->mbox -
((void *)&raid_dev->una_mbox64->mbox32));
raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 +
align;
// Allocate memory for commands issued internally
adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE,
&adapter->ibuf_dma_h);
if (!adapter->ibuf) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
goto fail_alloc_cmds;
}
alloc_ibuf_f = 1;
memset(adapter->ibuf, 0, MBOX_IBUF_SIZE);
// Allocate memory for our SCSI Command Blocks and their associated
// memory
/*
* Allocate memory for the base list of scb. Later allocate memory for
* CCBs and embedded components of each CCB and point the pointers in
* scb to the allocated components
* NOTE: The code to allocate SCB will be duplicated in all the LLD
* since the calling routine does not yet know the number of available
* commands.
*/
adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
GFP_KERNEL);
if (adapter->kscb_list == NULL) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
goto fail_alloc_cmds;
}
alloc_scb_f = 1;
memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
// memory allocation for our command packets
if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
goto fail_alloc_cmds;
}
dma_pools_f = 1;
// Adjust the scb pointers and link in the free pool
epthru_pci_blk = raid_dev->epthru_pool;
sg_pci_blk = raid_dev->sg_pool;
mbox_pci_blk = raid_dev->mbox_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
scb = adapter->kscb_list + i;
ccb = raid_dev->ccb_list + i;
ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16);
ccb->raw_mbox = (uint8_t *)ccb->mbox;
ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8);
ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16;
// make sure the mailbox is aligned properly
if (ccb->mbox_dma_h & 0x0F) {
con_log(CL_ANN, (KERN_CRIT
"megaraid mbox: not aligned on 16-bytes\n"));
goto fail_alloc_cmds;
}
ccb->epthru = (mraid_epassthru_t *)
epthru_pci_blk[i].vaddr;
ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr;
ccb->pthru = (mraid_passthru_t *)ccb->epthru;
ccb->pthru_dma_h = ccb->epthru_dma_h;
ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr;
ccb->sgl_dma_h = sg_pci_blk[i].dma_addr;
ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64;
scb->ccb = (caddr_t)ccb;
scb->gp = 0;
scb->sno = i; // command index
scb->scp = NULL;
scb->state = SCB_FREE;
scb->dma_direction = PCI_DMA_NONE;
scb->dma_type = MRAID_DMA_NONE;
scb->dev_channel = -1;
scb->dev_target = -1;
// put scb in the free pool
list_add_tail(&scb->list, &adapter->kscb_pool);
}
return 0;
fail_alloc_cmds:
if (dma_pools_f) {
megaraid_mbox_teardown_dma_pools(adapter);
}
if (alloc_scb_f) kfree(adapter->kscb_list);
if (alloc_ibuf_f) {
pci_free_consistent(pdev, MBOX_IBUF_SIZE,
(void *)adapter->ibuf, adapter->ibuf_dma_h);
}
if (alloc_common_mbox_f) {
pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
(caddr_t)raid_dev->una_mbox64,
raid_dev->una_mbox64_dma);
}
return -1;
}
/**
* megaraid_free_cmd_packets - free memory
* @param adapter : soft state of the raid controller
*
* Release memory resources allocated for commands
*/
static void
megaraid_free_cmd_packets(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
megaraid_mbox_teardown_dma_pools(adapter);
kfree(adapter->kscb_list);
pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE,
(void *)adapter->ibuf, adapter->ibuf_dma_h);
pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
return;
}
/**
* megaraid_mbox_setup_dma_pools - setup dma pool for command packets
* @param adapter : HBA soft state
*
* setup the dma pools for mailbox, passthru and extended passthru structures,
* and scatter-gather lists
*/
static int
megaraid_mbox_setup_dma_pools(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
struct mraid_pci_blk *epthru_pci_blk;
struct mraid_pci_blk *sg_pci_blk;
struct mraid_pci_blk *mbox_pci_blk;
int i;
// Allocate memory for 16-bytes aligned mailboxes
raid_dev->mbox_pool_handle = pci_pool_create("megaraid mbox pool",
adapter->pdev,
sizeof(mbox64_t) + 16,
16, 0);
if (raid_dev->mbox_pool_handle == NULL) {
goto fail_setup_dma_pool;
}
mbox_pci_blk = raid_dev->mbox_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
mbox_pci_blk[i].vaddr = pci_pool_alloc(
raid_dev->mbox_pool_handle,
GFP_KERNEL,
&mbox_pci_blk[i].dma_addr);
if (!mbox_pci_blk[i].vaddr) {
goto fail_setup_dma_pool;
}
}
/*
* Allocate memory for each embedded passthru strucuture pointer
* Request for a 128 bytes aligned structure for each passthru command
* structure
* Since passthru and extended passthru commands are exclusive, they
* share common memory pool. Passthru structures piggyback on memory
* allocted to extended passthru since passthru is smaller of the two
*/
raid_dev->epthru_pool_handle = pci_pool_create("megaraid mbox pthru",
adapter->pdev, sizeof(mraid_epassthru_t), 128, 0);
if (raid_dev->epthru_pool_handle == NULL) {
goto fail_setup_dma_pool;
}
epthru_pci_blk = raid_dev->epthru_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
epthru_pci_blk[i].vaddr = pci_pool_alloc(
raid_dev->epthru_pool_handle,
GFP_KERNEL,
&epthru_pci_blk[i].dma_addr);
if (!epthru_pci_blk[i].vaddr) {
goto fail_setup_dma_pool;
}
}
// Allocate memory for each scatter-gather list. Request for 512 bytes
// alignment for each sg list
raid_dev->sg_pool_handle = pci_pool_create("megaraid mbox sg",
adapter->pdev,
sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE,
512, 0);
if (raid_dev->sg_pool_handle == NULL) {
goto fail_setup_dma_pool;
}
sg_pci_blk = raid_dev->sg_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
sg_pci_blk[i].vaddr = pci_pool_alloc(
raid_dev->sg_pool_handle,
GFP_KERNEL,
&sg_pci_blk[i].dma_addr);
if (!sg_pci_blk[i].vaddr) {
goto fail_setup_dma_pool;
}
}
return 0;
fail_setup_dma_pool:
megaraid_mbox_teardown_dma_pools(adapter);
return -1;
}
/**
* megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets
* @param adapter : HBA soft state
*
* teardown the dma pool for mailbox, passthru and extended passthru
* structures, and scatter-gather lists
*/
static void
megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
struct mraid_pci_blk *epthru_pci_blk;
struct mraid_pci_blk *sg_pci_blk;
struct mraid_pci_blk *mbox_pci_blk;
int i;
sg_pci_blk = raid_dev->sg_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) {
pci_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr,
sg_pci_blk[i].dma_addr);
}
if (raid_dev->sg_pool_handle)
pci_pool_destroy(raid_dev->sg_pool_handle);
epthru_pci_blk = raid_dev->epthru_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) {
pci_pool_free(raid_dev->epthru_pool_handle,
epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr);
}
if (raid_dev->epthru_pool_handle)
pci_pool_destroy(raid_dev->epthru_pool_handle);
mbox_pci_blk = raid_dev->mbox_pool;
for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) {
pci_pool_free(raid_dev->mbox_pool_handle,
mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr);
}
if (raid_dev->mbox_pool_handle)
pci_pool_destroy(raid_dev->mbox_pool_handle);
return;
}
/**
* megaraid_queue_command - generic queue entry point for all LLDs
* @scp : pointer to the scsi command to be executed
* @done : callback routine to be called after the cmd has be completed
*
* Queue entry point for mailbox based controllers. This entry point is common
* for memory and IO based controllers
*/
static int
megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *))
{
adapter_t *adapter;
scb_t *scb;
int if_busy;
adapter = SCP2ADAPTER(scp);
scp->scsi_done = done;
scp->result = 0;
ASSERT(spin_is_locked(adapter->host_lock));
spin_unlock(adapter->host_lock);
/*
* Allocate and build a SCB request
* if_busy flag will be set if megaraid_mbox_build_cmd() command could
* not allocate scb. We will return non-zero status in that case.
* NOTE: scb can be null even though certain commands completed
* successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would
* return 0 in that case, and we would do the callback right away.
*/
if_busy = 0;
scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy);
if (scb) {
megaraid_mbox_runpendq(adapter, scb);
}
spin_lock(adapter->host_lock);
if (!scb) { // command already completed
done(scp);
}
return if_busy;
}
/**
* megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid
* firmware lingua
* @adapter - controller's soft state
* @scp - mid-layer scsi command pointer
* @busy - set if request could not be completed because of lack of
* resources
*
* convert the command issued by mid-layer to format understood by megaraid
* firmware. We also complete certain command without sending them to firmware
*/
static inline scb_t *
megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
{
mraid_device_t *rdev = ADAP2RAIDDEV(adapter);
int channel;
int target;
int islogical;
mbox_ccb_t *ccb;
mraid_passthru_t *pthru;
mbox64_t *mbox64;
mbox_t *mbox;
scb_t *scb;
char skip[] = "skipping";
char scan[] = "scanning";
char *ss;
/*
* Get the appropriate device map for the device this command is
* intended for
*/
MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical);
/*
* Logical drive commands
*/
if (islogical) {
switch (scp->cmnd[0]) {
case TEST_UNIT_READY:
/*
* Do we support clustering and is the support enabled
* If no, return success always
*/
if (!adapter->ha) {
scp->result = (DID_OK << 16);
return NULL;
}
if (!(scb = megaraid_alloc_scb(adapter, scp))) {
scp->result = (DID_ERROR << 16);
*busy = 1;
return NULL;
}
scb->dma_direction = scp->sc_data_direction;
scb->dev_channel = 0xFF;
scb->dev_target = target;
ccb = (mbox_ccb_t *)scb->ccb;
/*
* The command id will be provided by the command
* issuance routine
*/
ccb->raw_mbox[0] = CLUSTER_CMD;
ccb->raw_mbox[2] = RESERVATION_STATUS;
ccb->raw_mbox[3] = target;
return scb;
case MODE_SENSE:
if (scp->use_sg) {
struct scatterlist *sgl;
caddr_t vaddr;
sgl = (struct scatterlist *)scp->request_buffer;
if (sgl->page) {
vaddr = (caddr_t)
(page_address((&sgl[0])->page)
+ (&sgl[0])->offset);
memset(vaddr, 0, scp->cmnd[4]);
}
else {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: invalid sg:%d\n",
__LINE__));
}
}
else {
memset(scp->request_buffer, 0, scp->cmnd[4]);
}
scp->result = (DID_OK << 16);
return NULL;
case INQUIRY:
/*
* Display the channel scan for logical drives
* Do not display scan for a channel if already done.
*/
if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
con_log(CL_ANN, (KERN_INFO
"scsi[%d]: scanning scsi channel %d",
adapter->host->host_no,
SCP2CHANNEL(scp)));
con_log(CL_ANN, (
" [virtual] for logical drives\n"));
rdev->last_disp |= (1L << SCP2CHANNEL(scp));
}
/* Fall through */
case READ_CAPACITY:
/*
* Do not allow LUN > 0 for logical drives and
* requests for more than 40 logical drives
*/
if (SCP2LUN(scp)) {
scp->result = (DID_BAD_TARGET << 16);
return NULL;
}
if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) {
scp->result = (DID_BAD_TARGET << 16);
return NULL;
}
/* Allocate a SCB and initialize passthru */
if (!(scb = megaraid_alloc_scb(adapter, scp))) {
scp->result = (DID_ERROR << 16);
*busy = 1;
return NULL;
}
ccb = (mbox_ccb_t *)scb->ccb;
scb->dev_channel = 0xFF;
scb->dev_target = target;
pthru = ccb->pthru;
mbox = ccb->mbox;
mbox64 = ccb->mbox64;
pthru->timeout = 0;
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 1;
pthru->logdrv = target;
pthru->cdblen = scp->cmd_len;
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
mbox->cmd = MBOXCMD_PASSTHRU64;
scb->dma_direction = scp->sc_data_direction;
pthru->dataxferlen = scp->request_bufflen;
pthru->dataxferaddr = ccb->sgl_dma_h;
pthru->numsge = megaraid_mbox_mksgl(adapter,
scb);
mbox->xferaddr = 0xFFFFFFFF;
mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h;
mbox64->xferaddr_hi = 0;
return scb;
case READ_6:
case WRITE_6:
case READ_10:
case WRITE_10:
case READ_12:
case WRITE_12:
/*
* Allocate a SCB and initialize mailbox
*/
if (!(scb = megaraid_alloc_scb(adapter, scp))) {
scp->result = (DID_ERROR << 16);
*busy = 1;
return NULL;
}
ccb = (mbox_ccb_t *)scb->ccb;
scb->dev_channel = 0xFF;
scb->dev_target = target;
mbox = ccb->mbox;
mbox64 = ccb->mbox64;
mbox->logdrv = target;
/*
* A little HACK: 2nd bit is zero for all scsi read
* commands and is set for all scsi write commands
*/
mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64:
MBOXCMD_LREAD64 ;
/*
* 6-byte READ(0x08) or WRITE(0x0A) cdb
*/
if (scp->cmd_len == 6) {
mbox->numsectors = (uint32_t)scp->cmnd[4];
mbox->lba =
((uint32_t)scp->cmnd[1] << 16) |
((uint32_t)scp->cmnd[2] << 8) |
(uint32_t)scp->cmnd[3];
mbox->lba &= 0x1FFFFF;
}
/*
* 10-byte READ(0x28) or WRITE(0x2A) cdb
*/
else if (scp->cmd_len == 10) {
mbox->numsectors =
(uint32_t)scp->cmnd[8] |
((uint32_t)scp->cmnd[7] << 8);
mbox->lba =
((uint32_t)scp->cmnd[2] << 24) |
((uint32_t)scp->cmnd[3] << 16) |
((uint32_t)scp->cmnd[4] << 8) |
(uint32_t)scp->cmnd[5];
}
/*
* 12-byte READ(0xA8) or WRITE(0xAA) cdb
*/
else if (scp->cmd_len == 12) {
mbox->lba =
((uint32_t)scp->cmnd[2] << 24) |
((uint32_t)scp->cmnd[3] << 16) |
((uint32_t)scp->cmnd[4] << 8) |
(uint32_t)scp->cmnd[5];
mbox->numsectors =
((uint32_t)scp->cmnd[6] << 24) |
((uint32_t)scp->cmnd[7] << 16) |
((uint32_t)scp->cmnd[8] << 8) |
(uint32_t)scp->cmnd[9];
}
else {
con_log(CL_ANN, (KERN_WARNING
"megaraid: unsupported CDB length\n"));
megaraid_dealloc_scb(adapter, scb);
scp->result = (DID_ERROR << 16);
return NULL;
}
scb->dma_direction = scp->sc_data_direction;
// Calculate Scatter-Gather info
mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h;
mbox->numsge = megaraid_mbox_mksgl(adapter,
scb);
mbox->xferaddr = 0xFFFFFFFF;
mbox64->xferaddr_hi = 0;
return scb;
case RESERVE:
case RELEASE:
/*
* Do we support clustering and is the support enabled
*/
if (!adapter->ha) {
scp->result = (DID_BAD_TARGET << 16);
return NULL;
}
/*
* Allocate a SCB and initialize mailbox
*/
if (!(scb = megaraid_alloc_scb(adapter, scp))) {
scp->result = (DID_ERROR << 16);
*busy = 1;
return NULL;
}
ccb = (mbox_ccb_t *)scb->ccb;
scb->dev_channel = 0xFF;
scb->dev_target = target;
ccb->raw_mbox[0] = CLUSTER_CMD;
ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ?
RESERVE_LD : RELEASE_LD;
ccb->raw_mbox[3] = target;
scb->dma_direction = scp->sc_data_direction;
return scb;
default:
scp->result = (DID_BAD_TARGET << 16);
return NULL;
}
}
else { // Passthru device commands
// Do not allow access to target id > 15 or LUN > 7
if (target > 15 || SCP2LUN(scp) > 7) {
scp->result = (DID_BAD_TARGET << 16);
return NULL;
}
// if fast load option was set and scan for last device is
// over, reset the fast_load flag so that during a possible
// next scan, devices can be made available
if (rdev->fast_load && (target == 15) &&
(SCP2CHANNEL(scp) == adapter->max_channel -1)) {
con_log(CL_ANN, (KERN_INFO
"megaraid[%d]: physical device scan re-enabled\n",
adapter->host->host_no));
rdev->fast_load = 0;
}
/*
* Display the channel scan for physical devices
*/
if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
ss = rdev->fast_load ? skip : scan;
con_log(CL_ANN, (KERN_INFO
"scsi[%d]: %s scsi channel %d [Phy %d]",
adapter->host->host_no, ss, SCP2CHANNEL(scp),
channel));
con_log(CL_ANN, (
" for non-raid devices\n"));
rdev->last_disp |= (1L << SCP2CHANNEL(scp));
}
// disable channel sweep if fast load option given
if (rdev->fast_load) {
scp->result = (DID_BAD_TARGET << 16);
return NULL;
}
// Allocate a SCB and initialize passthru
if (!(scb = megaraid_alloc_scb(adapter, scp))) {
scp->result = (DID_ERROR << 16);
*busy = 1;
return NULL;
}
ccb = (mbox_ccb_t *)scb->ccb;
scb->dev_channel = channel;
scb->dev_target = target;
scb->dma_direction = scp->sc_data_direction;
mbox = ccb->mbox;
mbox64 = ccb->mbox64;
// Does this firmware support extended CDBs
if (adapter->max_cdb_sz == 16) {
mbox->cmd = MBOXCMD_EXTPTHRU;
megaraid_mbox_prepare_epthru(adapter, scb, scp);
mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h;
mbox64->xferaddr_hi = 0;
mbox->xferaddr = 0xFFFFFFFF;
}
else {
mbox->cmd = MBOXCMD_PASSTHRU64;
megaraid_mbox_prepare_pthru(adapter, scb, scp);
mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h;
mbox64->xferaddr_hi = 0;
mbox->xferaddr = 0xFFFFFFFF;
}
return scb;
}
}
/**
* megaraid_alloc_scb - detach and return a scb from the free list
* @adapter : controller's soft state
*
* return the scb from the head of the free list. NULL if there are none
* available
**/
static inline scb_t *
megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
{
struct list_head *head = &adapter->kscb_pool;
scb_t *scb = NULL;
unsigned long flags;
// detach scb from free pool
spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
if (list_empty(head)) {
spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
return NULL;
}
scb = list_entry(head->next, scb_t, list);
list_del_init(&scb->list);
spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
scb->state = SCB_ACTIVE;
scb->scp = scp;
scb->dma_type = MRAID_DMA_NONE;
return scb;
}
/**
* megaraid_dealloc_scb - return the scb to the free pool
* @adapter : controller's soft state
* @scb : scb to be freed
*
* return the scb back to the free list of scbs. The caller must 'flush' the
* SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc.
* NOTE NOTE: Make sure the scb is not on any list before calling this
* routine.
**/
static inline void
megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
{
unsigned long flags;
// put scb in the free pool
scb->state = SCB_FREE;
scb->scp = NULL;
spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
list_add(&scb->list, &adapter->kscb_pool);
spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
return;
}
/**
* megaraid_mbox_prepare_pthru - prepare a command for physical devices
* @adapter - pointer to controller's soft state
* @scb - scsi control block
* @scp - scsi command from the mid-layer
*
* prepare a command for the scsi physical devices
*/
static inline void
megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
struct scsi_cmnd *scp)
{
mbox_ccb_t *ccb;
mraid_passthru_t *pthru;
uint8_t channel;
uint8_t target;
ccb = (mbox_ccb_t *)scb->ccb;
pthru = ccb->pthru;
channel = scb->dev_channel;
target = scb->dev_target;
pthru->timeout = 1; // 0=6sec, 1=60sec, 2=10min, 3=3hrs
pthru->ars = 1;
pthru->islogical = 0;
pthru->channel = 0;
pthru->target = (channel << 4) | target;
pthru->logdrv = SCP2LUN(scp);
pthru->reqsenselen = 14;
pthru->cdblen = scp->cmd_len;
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
if (scp->request_bufflen) {
pthru->dataxferlen = scp->request_bufflen;
pthru->dataxferaddr = ccb->sgl_dma_h;
pthru->numsge = megaraid_mbox_mksgl(adapter, scb);
}
else {
pthru->dataxferaddr = 0;
pthru->dataxferlen = 0;
pthru->numsge = 0;
}
return;
}
/**
* megaraid_mbox_prepare_epthru - prepare a command for physical devices
* @adapter - pointer to controller's soft state
* @scb - scsi control block
* @scp - scsi command from the mid-layer
*
* prepare a command for the scsi physical devices. This rountine prepares
* commands for devices which can take extended CDBs (>10 bytes)
*/
static inline void
megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
struct scsi_cmnd *scp)
{
mbox_ccb_t *ccb;
mraid_epassthru_t *epthru;
uint8_t channel;
uint8_t target;
ccb = (mbox_ccb_t *)scb->ccb;
epthru = ccb->epthru;
channel = scb->dev_channel;
target = scb->dev_target;
epthru->timeout = 1; // 0=6sec, 1=60sec, 2=10min, 3=3hrs
epthru->ars = 1;
epthru->islogical = 0;
epthru->channel = 0;
epthru->target = (channel << 4) | target;
epthru->logdrv = SCP2LUN(scp);
epthru->reqsenselen = 14;
epthru->cdblen = scp->cmd_len;
memcpy(epthru->cdb, scp->cmnd, scp->cmd_len);
if (scp->request_bufflen) {
epthru->dataxferlen = scp->request_bufflen;
epthru->dataxferaddr = ccb->sgl_dma_h;
epthru->numsge = megaraid_mbox_mksgl(adapter, scb);
}
else {
epthru->dataxferaddr = 0;
epthru->dataxferlen = 0;
epthru->numsge = 0;
}
return;
}
/**
* megaraid_mbox_mksgl - make the scatter-gather list
* @adapter - controller's soft state
* @scb - scsi control block
*
* prepare the scatter-gather list
*/
static inline int
megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
{
struct scatterlist *sgl;
mbox_ccb_t *ccb;
struct page *page;
unsigned long offset;
struct scsi_cmnd *scp;
int sgcnt;
int i;
scp = scb->scp;
ccb = (mbox_ccb_t *)scb->ccb;
// no mapping required if no data to be transferred
if (!scp->request_buffer || !scp->request_bufflen)
return 0;
if (!scp->use_sg) { /* scatter-gather list not used */
page = virt_to_page(scp->request_buffer);
offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK);
ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset,
scp->request_bufflen,
scb->dma_direction);
scb->dma_type = MRAID_DMA_WBUF;
/*
* We need to handle special 64-bit commands that need a
* minimum of 1 SG
*/
sgcnt = 1;
ccb->sgl64[0].address = ccb->buf_dma_h;
ccb->sgl64[0].length = scp->request_bufflen;
return sgcnt;
}
sgl = (struct scatterlist *)scp->request_buffer;
// The number of sg elements returned must not exceed our limit
sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg,
scb->dma_direction);
if (sgcnt > adapter->sglen) {
con_log(CL_ANN, (KERN_CRIT
"megaraid critical: too many sg elements:%d\n",
sgcnt));
BUG();
}
scb->dma_type = MRAID_DMA_WSG;
for (i = 0; i < sgcnt; i++, sgl++) {
ccb->sgl64[i].address = sg_dma_address(sgl);
ccb->sgl64[i].length = sg_dma_len(sgl);
}
// Return count of SG nodes
return sgcnt;
}
/**
* megaraid_mbox_runpendq - execute commands queued in the pending queue
* @adapter : controller's soft state
* @scb : SCB to be queued in the pending list
*
* scan the pending list for commands which are not yet issued and try to
* post to the controller. The SCB can be a null pointer, which would indicate
* no SCB to be queue, just try to execute the ones in the pending list.
*
* NOTE: We do not actually traverse the pending list. The SCBs are plucked
* out from the head of the pending list. If it is successfully issued, the
* next SCB is at the head now.
*/
static inline void
megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q)
{
scb_t *scb;
unsigned long flags;
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
if (scb_q) {
scb_q->state = SCB_PENDQ;
list_add_tail(&scb_q->list, &adapter->pend_list);
}
// if the adapter in not in quiescent mode, post the commands to FW
if (adapter->quiescent) {
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
return;
}
while (!list_empty(&adapter->pend_list)) {
ASSERT(spin_is_locked(PENDING_LIST_LOCK(adapter)));
scb = list_entry(adapter->pend_list.next, scb_t, list);
// remove the scb from the pending list and try to
// issue. If we are unable to issue it, put back in
// the pending list and return
list_del_init(&scb->list);
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
// if mailbox was busy, return SCB back to pending
// list. Make sure to add at the head, since that's
// where it would have been removed from
scb->state = SCB_ISSUED;
if (mbox_post_cmd(adapter, scb) != 0) {
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
scb->state = SCB_PENDQ;
list_add(&scb->list, &adapter->pend_list);
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
flags);
return;
}
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
}
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
return;
}
/**
* mbox_post_cmd - issue a mailbox command
* @adapter - controller's soft state
* @scb - command to be issued
*
* post the command to the controller if mailbox is availble.
*/
static inline int
mbox_post_cmd(adapter_t *adapter, scb_t *scb)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mbox64_t *mbox64;
mbox_t *mbox;
mbox_ccb_t *ccb;
unsigned long flags;
unsigned int i = 0;
ccb = (mbox_ccb_t *)scb->ccb;
mbox = raid_dev->mbox;
mbox64 = raid_dev->mbox64;
/*
* Check for busy mailbox. If it is, return failure - the caller
* should retry later.
*/
spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
if (unlikely(mbox->busy)) {
do {
udelay(1);
i++;
rmb();
} while(mbox->busy && (i < max_mbox_busy_wait));
if (mbox->busy) {
spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
return -1;
}
}
// Copy this command's mailbox data into "adapter's" mailbox
memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 24);
mbox->cmdid = scb->sno;
adapter->outstanding_cmds++;
if (scb->dma_direction == PCI_DMA_TODEVICE) {
if (!scb->scp->use_sg) { // sg list not used
pci_dma_sync_single(adapter->pdev, ccb->buf_dma_h,
scb->scp->request_bufflen,
PCI_DMA_TODEVICE);
}
else {
pci_dma_sync_sg(adapter->pdev, scb->scp->request_buffer,
scb->scp->use_sg, PCI_DMA_TODEVICE);
}
}
mbox->busy = 1; // Set busy
mbox->poll = 0;
mbox->ack = 0;
wmb();
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
return 0;
}
/**
* megaraid_isr - isr for memory based mailbox based controllers
* @irq - irq
* @devp - pointer to our soft state
* @regs - unused
*
* Interrupt service routine for memory-mapped mailbox controllers.
*/
static irqreturn_t
megaraid_isr(int irq, void *devp, struct pt_regs *regs)
{
adapter_t *adapter = devp;
int handled;
handled = megaraid_ack_sequence(adapter);
/* Loop through any pending requests */
if (!adapter->quiescent) {
megaraid_mbox_runpendq(adapter, 0);
}
return IRQ_RETVAL(handled);
}
/**
* megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs
* @adapter - controller's soft state
*
* Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the
* completed command and put them on the completed list for later processing.
*
* Returns: 1 if the interrupt is valid, 0 otherwise
*/
static inline int
megaraid_ack_sequence(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mbox_t *mbox;
scb_t *scb;
uint8_t nstatus;
uint8_t completed[MBOX_MAX_FIRMWARE_STATUS];
struct list_head clist;
int handled;
uint32_t dword;
unsigned long flags;
int i, j;
mbox = raid_dev->mbox;
// move the SCBs from the firmware completed array to our local list
INIT_LIST_HEAD(&clist);
// loop till F/W has more commands for us to complete
handled = 0;
spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
do {
/*
* Check if a valid interrupt is pending. If found, force the
* interrupt line low.
*/
dword = RDOUTDOOR(raid_dev);
if (dword != 0x10001234) break;
handled = 1;
WROUTDOOR(raid_dev, 0x10001234);
nstatus = 0;
// wait for valid numstatus to post
for (i = 0; i < 0xFFFFF; i++) {
if (mbox->numstatus != 0xFF) {
nstatus = mbox->numstatus;
break;
}
rmb();
}
mbox->numstatus = 0xFF;
adapter->outstanding_cmds -= nstatus;
for (i = 0; i < nstatus; i++) {
// wait for valid command index to post
for (j = 0; j < 0xFFFFF; j++) {
if (mbox->completed[i] != 0xFF) break;
rmb();
}
completed[i] = mbox->completed[i];
mbox->completed[i] = 0xFF;
if (completed[i] == 0xFF) {
con_log(CL_ANN, (KERN_CRIT
"megaraid: command posting timed out\n"));
BUG();
continue;
}
// Get SCB associated with this command id
if (completed[i] >= MBOX_MAX_SCSI_CMDS) {
// a cmm command
scb = adapter->uscb_list + (completed[i] -
MBOX_MAX_SCSI_CMDS);
}
else {
// an os command
scb = adapter->kscb_list + completed[i];
}
scb->status = mbox->status;
list_add_tail(&scb->list, &clist);
}
// Acknowledge interrupt
WRINDOOR(raid_dev, 0x02);
} while(1);
spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
// put the completed commands in the completed list. DPC would
// complete these commands later
spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
list_splice(&clist, &adapter->completed_list);
spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
// schedule the DPC if there is some work for it
if (handled)
tasklet_schedule(&adapter->dpc_h);
return handled;
}
/**
* megaraid_mbox_dpc - the tasklet to complete the commands from completed list
* @devp : pointer to HBA soft state
*
* Pick up the commands from the completed list and send back to the owners.
* This is a reentrant function and does not assume any locks are held while
* it is being called.
*/
static void
megaraid_mbox_dpc(unsigned long devp)
{
adapter_t *adapter = (adapter_t *)devp;
mraid_device_t *raid_dev;
struct list_head clist;
struct scatterlist *sgl;
scb_t *scb;
scb_t *tmp;
struct scsi_cmnd *scp;
mraid_passthru_t *pthru;
mraid_epassthru_t *epthru;
mbox_ccb_t *ccb;
int islogical;
int pdev_index;
int pdev_state;
mbox_t *mbox;
unsigned long flags;
uint8_t c;
int status;
if (!adapter) return;
raid_dev = ADAP2RAIDDEV(adapter);
// move the SCBs from the completed list to our local list
INIT_LIST_HEAD(&clist);
spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
list_splice_init(&adapter->completed_list, &clist);
spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
list_for_each_entry_safe(scb, tmp, &clist, list) {
status = scb->status;
scp = scb->scp;
ccb = (mbox_ccb_t *)scb->ccb;
pthru = ccb->pthru;
epthru = ccb->epthru;
mbox = ccb->mbox;
// Make sure f/w has completed a valid command
if (scb->state != SCB_ISSUED) {
con_log(CL_ANN, (KERN_CRIT
"megaraid critical err: invalid command %d:%d:%p\n",
scb->sno, scb->state, scp));
BUG();
continue; // Must never happen!
}
// check for the management command and complete it right away
if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
scb->state = SCB_FREE;
scb->status = status;
// remove from local clist
list_del_init(&scb->list);
megaraid_mbox_mm_done(adapter, scb);
continue;
}
// Was an abort issued for this command earlier
if (scb->state & SCB_ABORT) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: aborted cmd %lx[%x] completed\n",
scp->serial_number, scb->sno));
}
/*
* If the inquiry came of a disk drive which is not part of
* any RAID array, expose it to the kernel. For this to be
* enabled, user must set the "megaraid_expose_unconf_disks"
* flag to 1 by specifying it on module parameter list.
* This would enable data migration off drives from other
* configurations.
*/
islogical = MRAID_IS_LOGICAL(adapter, scp);
if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0
&& IS_RAID_CH(raid_dev, scb->dev_channel)) {
if (scp->use_sg) {
sgl = (struct scatterlist *)
scp->request_buffer;
if (sgl->page) {
c = *(unsigned char *)
(page_address((&sgl[0])->page) +
(&sgl[0])->offset);
}
else {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: invalid sg:%d\n",
__LINE__));
c = 0;
}
}
else {
c = *(uint8_t *)scp->request_buffer;
}
if ((c & 0x1F ) == TYPE_DISK) {
pdev_index = (scb->dev_channel * 16) +
scb->dev_target;
pdev_state =
raid_dev->pdrv_state[pdev_index] & 0x0F;
if (pdev_state == PDRV_ONLINE ||
pdev_state == PDRV_FAILED ||
pdev_state == PDRV_RBLD ||
pdev_state == PDRV_HOTSPARE ||
megaraid_expose_unconf_disks == 0) {
status = 0xF0;
}
}
}
// Convert MegaRAID status to Linux error code
switch (status) {
case 0x00:
scp->result = (DID_OK << 16);
break;
case 0x02:
/* set sense_buffer and result fields */
if (mbox->cmd == MBOXCMD_PASSTHRU ||
mbox->cmd == MBOXCMD_PASSTHRU64) {
memcpy(scp->sense_buffer, pthru->reqsensearea,
14);
scp->result = DRIVER_SENSE << 24 |
DID_OK << 16 | CHECK_CONDITION << 1;
}
else {
if (mbox->cmd == MBOXCMD_EXTPTHRU) {
memcpy(scp->sense_buffer,
epthru->reqsensearea, 14);
scp->result = DRIVER_SENSE << 24 |
DID_OK << 16 |
CHECK_CONDITION << 1;
} else {
scp->sense_buffer[0] = 0x70;
scp->sense_buffer[2] = ABORTED_COMMAND;
scp->result = CHECK_CONDITION << 1;
}
}
break;
case 0x08:
scp->result = DID_BUS_BUSY << 16 | status;
break;
default:
/*
* If TEST_UNIT_READY fails, we know RESERVATION_STATUS
* failed
*/
if (scp->cmnd[0] == TEST_UNIT_READY) {
scp->result = DID_ERROR << 16 |
RESERVATION_CONFLICT << 1;
}
else
/*
* Error code returned is 1 if Reserve or Release
* failed or the input parameter is invalid
*/
if (status == 1 && (scp->cmnd[0] == RESERVE ||
scp->cmnd[0] == RELEASE)) {
scp->result = DID_ERROR << 16 |
RESERVATION_CONFLICT << 1;
}
else {
scp->result = DID_BAD_TARGET << 16 | status;
}
}
// print a debug message for all failed commands
if (status) {
megaraid_mbox_display_scb(adapter, scb);
}
// Free our internal resources and call the mid-layer callback
// routine
megaraid_mbox_sync_scb(adapter, scb);
// remove from local clist
list_del_init(&scb->list);
// put back in free list
megaraid_dealloc_scb(adapter, scb);
// send the scsi packet back to kernel
spin_lock(adapter->host_lock);
scp->scsi_done(scp);
spin_unlock(adapter->host_lock);
}
return;
}
/**
* megaraid_mbox_sync_scb - sync kernel buffers
* @adapter : controller's soft state
* @scb : pointer to the resource packet
*
* DMA sync if required.
*/
static inline void
megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
{
mbox_ccb_t *ccb;
ccb = (mbox_ccb_t *)scb->ccb;
switch (scb->dma_type) {
case MRAID_DMA_WBUF:
if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
pci_dma_sync_single(adapter->pdev,
ccb->buf_dma_h,
scb->scp->request_bufflen,
PCI_DMA_FROMDEVICE);
}
pci_unmap_page(adapter->pdev, ccb->buf_dma_h,
scb->scp->request_bufflen, scb->dma_direction);
break;
case MRAID_DMA_WSG:
if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
pci_dma_sync_sg(adapter->pdev,
scb->scp->request_buffer,
scb->scp->use_sg, PCI_DMA_FROMDEVICE);
}
pci_unmap_sg(adapter->pdev, scb->scp->request_buffer,
scb->scp->use_sg, scb->dma_direction);
break;
default:
break;
}
return;
}
/**
* megaraid_abort_handler - abort the scsi command
* @scp : command to be aborted
*
* Abort a previous SCSI request. Only commands on the pending list can be
* aborted. All the commands issued to the F/W must complete.
**/
static int
megaraid_abort_handler(struct scsi_cmnd *scp)
{
adapter_t *adapter;
mraid_device_t *raid_dev;
scb_t *scb;
scb_t *tmp;
int found;
unsigned long flags;
int i;
adapter = SCP2ADAPTER(scp);
raid_dev = ADAP2RAIDDEV(adapter);
ASSERT(spin_is_locked(adapter->host_lock));
con_log(CL_ANN, (KERN_WARNING
"megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp),
SCP2TARGET(scp), SCP2LUN(scp)));
// If FW has stopped responding, simply return failure
if (raid_dev->hw_error) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: hw error, not aborting\n"));
return FAILED;
}
// There might a race here, where the command was completed by the
// firmware and now it is on the completed list. Before we could
// complete the command to the kernel in dpc, the abort came.
// Find out if this is the case to avoid the race.
scb = NULL;
spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) {
if (scb->scp == scp) { // Found command
list_del_init(&scb->list); // from completed list
con_log(CL_ANN, (KERN_WARNING
"megaraid: %ld:%d[%d:%d], abort from completed list\n",
scp->serial_number, scb->sno,
scb->dev_channel, scb->dev_target));
scp->result = (DID_ABORT << 16);
scp->scsi_done(scp);
megaraid_dealloc_scb(adapter, scb);
spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter),
flags);
return SUCCESS;
}
}
spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
// Find out if this command is still on the pending list. If it is and
// was never issued, abort and return success. If the command is owned
// by the firmware, we must wait for it to complete by the FW.
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
if (scb->scp == scp) { // Found command
list_del_init(&scb->list); // from pending list
ASSERT(!(scb->state & SCB_ISSUED));
con_log(CL_ANN, (KERN_WARNING
"megaraid abort: %ld[%d:%d], driver owner\n",
scp->serial_number, scb->dev_channel,
scb->dev_target));
scp->result = (DID_ABORT << 16);
scp->scsi_done(scp);
megaraid_dealloc_scb(adapter, scb);
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
flags);
return SUCCESS;
}
}
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
// Check do we even own this command, in which case this would be
// owned by the firmware. The only way to locate the FW scb is to
// traverse through the list of all SCB, since driver does not
// maintain these SCBs on any list
found = 0;
for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
scb = adapter->kscb_list + i;
if (scb->scp == scp) {
found = 1;
if (!(scb->state & SCB_ISSUED)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid abort: %ld%d[%d:%d], invalid state\n",
scp->serial_number, scb->sno, scb->dev_channel,
scb->dev_target));
BUG();
}
else {
con_log(CL_ANN, (KERN_WARNING
"megaraid abort: %ld:%d[%d:%d], fw owner\n",
scp->serial_number, scb->sno, scb->dev_channel,
scb->dev_target));
}
}
}
if (!found) {
con_log(CL_ANN, (KERN_WARNING
"megaraid abort: %ld:%d[%d:%d], do now own\n",
scp->serial_number, scb->sno, scb->dev_channel,
scb->dev_target));
// FIXME: Should there be a callback for this command?
return SUCCESS;
}
// We cannot actually abort a command owned by firmware, return
// failure and wait for reset. In host reset handler, we will find out
// if the HBA is still live
return FAILED;
}
/**
* megaraid_reset_handler - device reset hadler for mailbox based driver
* @scp : reference command
*
* Reset handler for the mailbox based controller. First try to find out if
* the FW is still live, in which case the outstanding commands counter mut go
* down to 0. If that happens, also issue the reservation reset command to
* relinquish (possible) reservations on the logical drives connected to this
* host
**/
static int
megaraid_reset_handler(struct scsi_cmnd *scp)
{
adapter_t *adapter;
scb_t *scb;
scb_t *tmp;
mraid_device_t *raid_dev;
unsigned long flags;
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
int recovery_window;
int recovering;
int i;
DECLARE_WAIT_QUEUE_HEAD(wq);
adapter = SCP2ADAPTER(scp);
raid_dev = ADAP2RAIDDEV(adapter);
ASSERT(spin_is_locked(adapter->host_lock));
con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n"));
// return failure if adapter is not responding
if (raid_dev->hw_error) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: hw error, cannot reset\n"));
return FAILED;
}
// Under exceptional conditions, FW can take up to 3 minutes to
// complete command processing. Wait for additional 3 minutes for the
// pending commands counter to go down to 0. If it doesn't, let the
// controller be marked offline
// Also, reset all the commands currently owned by the driver
spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
list_del_init(&scb->list); // from pending list
con_log(CL_ANN, (KERN_WARNING
"megaraid: %ld:%d[%d:%d], reset from pending list\n",
scp->serial_number, scb->sno,
scb->dev_channel, scb->dev_target));
scp->result = (DID_RESET << 16);
scp->scsi_done(scp);
megaraid_dealloc_scb(adapter, scb);
}
spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
if (adapter->outstanding_cmds) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid: %d outstanding commands. Max wait %d sec\n",
adapter->outstanding_cmds, MBOX_RESET_WAIT));
}
spin_unlock(adapter->host_lock);
recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
recovering = adapter->outstanding_cmds;
for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) {
megaraid_ack_sequence(adapter);
// print a message once every 5 seconds only
if (!(i % 5)) {
con_log(CL_ANN, (
"megaraid mbox: Wait for %d commands to complete:%d\n",
adapter->outstanding_cmds,
MBOX_RESET_WAIT - i));
}
// bailout if no recovery happended in reset time
if ((i == MBOX_RESET_WAIT) &&
(recovering == adapter->outstanding_cmds)) {
break;
}
//msleep(1000);
sleep_on_timeout(&wq, HZ);
}
spin_lock(adapter->host_lock);
// If still outstanding commands, bail out
if (adapter->outstanding_cmds) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mbox: critical hardware error!\n"));
raid_dev->hw_error = 1;
return FAILED;
}
else {
con_log(CL_ANN, (KERN_NOTICE
"megaraid mbox: reset sequence completed sucessfully\n"));
}
// If the controller supports clustering, reset reservations
if (!adapter->ha) return SUCCESS;
// clear reservations if any
raw_mbox[0] = CLUSTER_CMD;
raw_mbox[2] = RESET_RESERVATIONS;
rval = SUCCESS;
if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) {
con_log(CL_ANN,
(KERN_INFO "megaraid: reservation reset\n"));
}
else {
rval = FAILED;
con_log(CL_ANN, (KERN_WARNING
"megaraid: reservation reset failed\n"));
}
return rval;
}
/*
* START: internal commands library
*
* This section of the driver has the common routine used by the driver and
* also has all the FW routines
*/
/**
* mbox_post_sync_cmd() - blocking command to the mailbox based controllers
* @adapter - controller's soft state
* @raw_mbox - the mailbox
*
* Issue a scb in synchronous and non-interrupt mode for mailbox based
* controllers
*/
static int
mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[])
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mbox64_t *mbox64;
mbox_t *mbox;
uint8_t status;
long i;
mbox64 = raid_dev->mbox64;
mbox = raid_dev->mbox;
/*
* Wait until mailbox is free
*/
if (megaraid_busywait_mbox(raid_dev) != 0)
goto blocked_mailbox;
/*
* Copy mailbox data into host structure
*/
memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
mbox->cmdid = 0xFE;
mbox->busy = 1;
mbox->poll = 0;
mbox->ack = 0;
mbox->numstatus = 0xFF;
mbox->status = 0xFF;
wmb();
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
// wait for maximum 1 second for status to post
for (i = 0; i < 40000; i++) {
if (mbox->numstatus != 0xFF) break;
udelay(25); yield();
}
if (i == 40000) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: status not available\n"));
return -1;
}
// wait for maximum 1 second for poll semaphore
for (i = 0; i < 40000; i++) {
if (mbox->poll == 0x77) break;
udelay(25); yield();
}
if (i == 40000) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: could not get poll semaphore\n"));
return -1;
}
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
wmb();
// wait for maximum 1 second for acknowledgement
for (i = 0; i < 40000; i++) {
if ((RDINDOOR(raid_dev) & 0x2) == 0) {
mbox->poll = 0;
mbox->ack = 0x77;
break;
}
udelay(25); yield();
}
if (i == 40000) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: could not acknowledge\n"));
return -1;
}
status = mbox->status;
// invalidate the completed command id array. After command
// completion, firmware would write the valid id.
mbox->numstatus = 0xFF;
mbox->status = 0xFF;
for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) {
mbox->completed[i] = 0xFF;
}
return status;
blocked_mailbox:
con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") );
return -1;
}
/**
* mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers
* @adapter - controller's soft state
* @raw_mbox - the mailbox
*
* Issue a scb in synchronous and non-interrupt mode for mailbox based
* controllers. This is a faster version of the synchronous command and
* therefore can be called in interrupt-context as well
*/
static int
mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mbox_t *mbox;
long i;
mbox = raid_dev->mbox;
// return immediately if the mailbox is busy
if (mbox->busy) return -1;
// Copy mailbox data into host structure
memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
mbox->cmdid = 0xFE;
mbox->busy = 1;
mbox->poll = 0;
mbox->ack = 0;
mbox->numstatus = 0xFF;
mbox->status = 0xFF;
wmb();
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
for (i = 0; i < 0xFFFFF; i++) {
if (mbox->numstatus != 0xFF) break;
}
if (i == 0xFFFFF) {
// We may need to re-calibrate the counter
con_log(CL_ANN, (KERN_CRIT
"megaraid: fast sync command timed out\n"));
}
WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
wmb();
return mbox->status;
}
/**
* megaraid_busywait_mbox() - Wait until the controller's mailbox is available
* @raid_dev - RAID device (HBA) soft state
*
* wait until the controller's mailbox is available to accept more commands.
*/
static inline int
megaraid_busywait_mbox(mraid_device_t *raid_dev)
{
mbox_t *mbox = raid_dev->mbox;
if (mbox->busy)
return __megaraid_busywait_mbox(raid_dev);
return 0;
}
/**
* __megaraid_busywait_mbox() - Wait until controller's mailbox is available
* @raid_dev - mailbox data structures
*
* wait until the controller's mailbox is available to accept more commands.
*/
static inline int
__megaraid_busywait_mbox(mraid_device_t *raid_dev)
{
mbox_t *mbox = raid_dev->mbox;
unsigned long counter;
for (counter = 0; counter < 10000; counter++) {
if (!mbox->busy) return 0;
udelay(100); yield();
}
return -1; // give up after 1 second
}
/**
* megaraid_mbox_product_info - some static information about the controller
* @adapter - our soft state
*
* issue commands to the controller to grab some parameters required by our
* caller.
*/
static int
megaraid_mbox_product_info(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
mraid_pinfo_t *pinfo;
dma_addr_t pinfo_dma_h;
mraid_inquiry3_t *mraid_inq3;
int i;
mbox = (mbox_t *)raw_mbox;
/*
* Issue an ENQUIRY3 command to find out certain adapter parameters,
* e.g., max channels, max commands etc.
*/
pinfo = pci_alloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
&pinfo_dma_h);
if (pinfo == NULL) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
return -1;
}
memset(pinfo, 0, sizeof(mraid_pinfo_t));
mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
raw_mbox[0] = FC_NEW_CONFIG;
raw_mbox[2] = NC_SUBOP_ENQUIRY3;
raw_mbox[3] = ENQ3_GET_SOLICITED_FULL;
// Issue the command
if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n"));
pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
pinfo, pinfo_dma_h);
return -1;
}
/*
* Collect information about state of each physical drive
* attached to the controller. We will expose all the disks
* which are not part of RAID
*/
mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf;
for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) {
raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i];
}
/*
* Get product info for information like number of channels,
* maximum commands supported.
*/
memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
mbox->xferaddr = (uint32_t)pinfo_dma_h;
raw_mbox[0] = FC_NEW_CONFIG;
raw_mbox[2] = NC_SUBOP_PRODUCT_INFO;
if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: product info failed\n"));
pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
pinfo, pinfo_dma_h);
return -1;
}
/*
* Setup some parameters for host, as required by our caller
*/
adapter->max_channel = pinfo->nchannels;
/*
* we will export all the logical drives on a single channel.
* Add 1 since inquires do not come for inititor ID
*/
adapter->max_target = MAX_LOGICAL_DRIVES_40LD + 1;
adapter->max_lun = 8; // up to 8 LUNs for non-disk devices
/*
* These are the maximum outstanding commands for the scsi-layer
*/
adapter->max_cmds = MBOX_MAX_SCSI_CMDS;
memset(adapter->fw_version, 0, VERSION_SIZE);
memset(adapter->bios_version, 0, VERSION_SIZE);
memcpy(adapter->fw_version, pinfo->fw_version, 4);
adapter->fw_version[4] = 0;
memcpy(adapter->bios_version, pinfo->bios_version, 4);
adapter->bios_version[4] = 0;
con_log(CL_ANN, (KERN_NOTICE
"megaraid: fw version:[%s] bios version:[%s]\n",
adapter->fw_version, adapter->bios_version));
pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo,
pinfo_dma_h);
return 0;
}
/**
* megaraid_mbox_extended_cdb - check for support for extended CDBs
* @adapter - soft state for the controller
*
* this routine check whether the controller in question supports extended
* ( > 10 bytes ) CDBs
*/
static int
megaraid_mbox_extended_cdb(adapter_t *adapter)
{
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
mbox = (mbox_t *)raw_mbox;
memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
raw_mbox[0] = MAIN_MISC_OPCODE;
raw_mbox[2] = SUPPORT_EXT_CDB;
/*
* Issue the command
*/
rval = 0;
if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
rval = -1;
}
return rval;
}
/**
* megaraid_mbox_support_ha - Do we support clustering
* @adapter - soft state for the controller
* @init_id - ID of the initiator
*
* Determine if the firmware supports clustering and the ID of the initiator.
*/
static int
megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id)
{
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
mbox = (mbox_t *)raw_mbox;
memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
raw_mbox[0] = GET_TARGET_ID;
// Issue the command
*init_id = 7;
rval = -1;
if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
*init_id = *(uint8_t *)adapter->ibuf;
con_log(CL_ANN, (KERN_INFO
"megaraid: cluster firmware, initiator ID: %d\n",
*init_id));
rval = 0;
}
return rval;
}
/**
* megaraid_mbox_support_random_del - Do we support random deletion
* @adapter - soft state for the controller
*
* Determine if the firmware supports random deletion
* Return: 1 is operation supported, 0 otherwise
*/
static int
megaraid_mbox_support_random_del(adapter_t *adapter)
{
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
mbox = (mbox_t *)raw_mbox;
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
raw_mbox[0] = FC_DEL_LOGDRV;
raw_mbox[0] = OP_SUP_DEL_LOGDRV;
// Issue the command
rval = 0;
if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n"));
rval = 1;
}
return rval;
}
/**
* megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware
* @adapter - soft state for the controller
*
* Find out the maximum number of scatter-gather elements supported by the
* firmware
*/
static int
megaraid_mbox_get_max_sg(adapter_t *adapter)
{
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
int nsg;
mbox = (mbox_t *)raw_mbox;
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
raw_mbox[0] = MAIN_MISC_OPCODE;
raw_mbox[2] = GET_MAX_SG_SUPPORT;
// Issue the command
if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
nsg = *(uint8_t *)adapter->ibuf;
}
else {
nsg = MBOX_DEFAULT_SG_SIZE;
}
if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE;
return nsg;
}
/**
* megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels
* @adapter - soft state for the controller
*
* Enumerate the RAID and SCSI channels for ROMB platoforms so that channels
* can be exported as regular SCSI channels
*/
static void
megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
mbox = (mbox_t *)raw_mbox;
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
raw_mbox[0] = CHNL_CLASS;
raw_mbox[2] = GET_CHNL_CLASS;
// Issue the command. If the command fails, all channels are RAID
// channels
raid_dev->channel_class = 0xFF;
if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
raid_dev->channel_class = *(uint8_t *)adapter->ibuf;
}
return;
}
/**
* megaraid_mbox_flush_cache - flush adapter and disks cache
* @param adapter : soft state for the controller
*
* Flush adapter cache followed by disks cache
*/
static void
megaraid_mbox_flush_cache(adapter_t *adapter)
{
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
mbox = (mbox_t *)raw_mbox;
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
raw_mbox[0] = FLUSH_ADAPTER;
if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
con_log(CL_ANN, ("megaraid: flush adapter failed\n"));
}
raw_mbox[0] = FLUSH_SYSTEM;
if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
con_log(CL_ANN, ("megaraid: flush disks cache failed\n"));
}
return;
}
/**
* megaraid_mbox_display_scb - display SCB information, mostly debug purposes
* @param adapter : controllers' soft state
* @param scb : SCB to be displayed
* @param level : debug level for console print
*
* Diplay information about the given SCB iff the current debug level is
* verbose
*/
static void
megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb)
{
mbox_ccb_t *ccb;
struct scsi_cmnd *scp;
mbox_t *mbox;
int level;
int i;
ccb = (mbox_ccb_t *)scb->ccb;
scp = scb->scp;
mbox = ccb->mbox;
level = CL_DLEVEL3;
con_log(level, (KERN_NOTICE
"megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status,
mbox->cmd, scb->sno));
con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n",
mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv,
mbox->numsge));
if (!scp) return;
con_log(level, (KERN_NOTICE "scsi cmnd: "));
for (i = 0; i < scp->cmd_len; i++) {
con_log(level, ("%#2.02x ", scp->cmnd[i]));
}
con_log(level, ("\n"));
return;
}
/**
* megaraid_mbox_setup_device_map - manage device ids
* @adapter : Driver's soft state
*
* Manange the device ids to have an appropraite mapping between the kernel
* scsi addresses and megaraid scsi and logical drive addresses. We export
* scsi devices on their actual addresses, whereas the logical drives are
* exported on a virtual scsi channel.
**/
static void
megaraid_mbox_setup_device_map(adapter_t *adapter)
{
uint8_t c;
uint8_t t;
/*
* First fill the values on the logical drive channel
*/
for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
adapter->device_ids[adapter->max_channel][t] =
(t < adapter->init_id) ? t : t - 1;
adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF;
/*
* Fill the values on the physical devices channels
*/
for (c = 0; c < adapter->max_channel; c++)
for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
adapter->device_ids[c][t] = (c << 8) | t;
}
/*
* END: internal commands library
*/
/*
* START: Interface for the common management module
*
* This is the module, which interfaces with the common mangement module to
* provide support for ioctl and sysfs
*/
/**
* megaraid_cmm_register - register with the mangement module
* @param adapter : HBA soft state
*
* Register with the management module, which allows applications to issue
* ioctl calls to the drivers. This interface is used by the management module
* to setup sysfs support as well.
*/
static int
megaraid_cmm_register(adapter_t *adapter)
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
mraid_mmadp_t adp;
scb_t *scb;
mbox_ccb_t *ccb;
int rval;
int i;
// Allocate memory for the base list of scb for management module.
adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
GFP_KERNEL);
if (adapter->uscb_list == NULL) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
return -1;
}
memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
// Initialize the synchronization parameters for resources for
// commands for management module
INIT_LIST_HEAD(&adapter->uscb_pool);
spin_lock_init(USER_FREE_LIST_LOCK(adapter));
// link all the packets. Note, CCB for commands, coming from the
// commom management module, mailbox physical address are already
// setup by it. We just need placeholder for that in our local command
// control blocks
for (i = 0; i < MBOX_MAX_USER_CMDS; i++) {
scb = adapter->uscb_list + i;
ccb = raid_dev->ccb_list + i;
scb->ccb = (caddr_t)ccb;
ccb->mbox64 = raid_dev->umbox64 + i;
ccb->mbox = &ccb->mbox64->mbox32;
ccb->raw_mbox = (uint8_t *)ccb->mbox;
scb->gp = 0;
// COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR
// COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER)
scb->sno = i + MBOX_MAX_SCSI_CMDS;
scb->scp = NULL;
scb->state = SCB_FREE;
scb->dma_direction = PCI_DMA_NONE;
scb->dma_type = MRAID_DMA_NONE;
scb->dev_channel = -1;
scb->dev_target = -1;
// put scb in the free pool
list_add_tail(&scb->list, &adapter->uscb_pool);
}
adp.unique_id = adapter->unique_id;
adp.drvr_type = DRVRTYPE_MBOX;
adp.drvr_data = (unsigned long)adapter;
adp.pdev = adapter->pdev;
adp.issue_uioc = megaraid_mbox_mm_handler;
adp.timeout = 30;
adp.max_kioc = MBOX_MAX_USER_CMDS;
if ((rval = mraid_mm_register_adp(&adp)) != 0) {
con_log(CL_ANN, (KERN_WARNING
"megaraid mbox: did not register with CMM\n"));
kfree(adapter->uscb_list);
}
return rval;
}
/**
* megaraid_cmm_unregister - un-register with the mangement module
* @param adapter : HBA soft state
*
* Un-register with the management module.
* FIXME: mgmt module must return failure for unregister if it has pending
* commands in LLD
*/
static int
megaraid_cmm_unregister(adapter_t *adapter)
{
kfree(adapter->uscb_list);
mraid_mm_unregister_adp(adapter->unique_id);
return 0;
}
/**
* megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD
* @param drvr_data : LLD specific data
* @param kioc : CMM interface packet
* @param action : command action
*
* This routine is invoked whenever the Common Mangement Module (CMM) has a
* command for us. The 'action' parameter specifies if this is a new command
* or otherwise.
*/
static int
megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action)
{
adapter_t *adapter;
if (action != IOCTL_ISSUE) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: unsupported management action:%#2x\n",
action));
return (-ENOTSUPP);
}
adapter = (adapter_t *)drvr_data;
// make sure this adapter is not being detached right now.
if (atomic_read(&adapter->being_detached)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: reject management request, detaching\n"));
return (-ENODEV);
}
switch (kioc->opcode) {
case GET_ADAP_INFO:
kioc->status = gather_hbainfo(adapter, (mraid_hba_info_t *)
(unsigned long)kioc->buf_vaddr);
kioc->done(kioc);
return kioc->status;
case MBOX_CMD:
return megaraid_mbox_mm_command(adapter, kioc);
default:
kioc->status = (-EINVAL);
kioc->done(kioc);
return (-EINVAL);
}
return 0; // not reached
}
/**
* megaraid_mbox_mm_command - issues commands routed through CMM
* @param adapter : HBA soft state
* @param kioc : management command packet
*
* Issues commands, which are routed through the management module.
*/
static int
megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc)
{
struct list_head *head = &adapter->uscb_pool;
mbox64_t *mbox64;
uint8_t *raw_mbox;
scb_t *scb;
mbox_ccb_t *ccb;
unsigned long flags;
// detach one scb from free pool
spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
if (list_empty(head)) { // should never happen because of CMM
con_log(CL_ANN, (KERN_WARNING
"megaraid mbox: bug in cmm handler, lost resources\n"));
spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
return (-EINVAL);
}
scb = list_entry(head->next, scb_t, list);
list_del_init(&scb->list);
spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
scb->state = SCB_ACTIVE;
scb->dma_type = MRAID_DMA_NONE;
ccb = (mbox_ccb_t *)scb->ccb;
mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
raw_mbox = (uint8_t *)&mbox64->mbox32;
memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t));
scb->gp = (unsigned long)kioc;
/*
* If it is a logdrv random delete operation, we have to wait till
* there are no outstanding cmds at the fw and then issue it directly
*/
if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
if (wait_till_fw_empty(adapter)) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid mbox: LD delete, timed out\n"));
kioc->status = -ETIME;
scb->status = -1;
megaraid_mbox_mm_done(adapter, scb);
return (-ETIME);
}
INIT_LIST_HEAD(&scb->list);
scb->state = SCB_ISSUED;
if (mbox_post_cmd(adapter, scb) != 0) {
con_log(CL_ANN, (KERN_NOTICE
"megaraid mbox: LD delete, mailbox busy\n"));
kioc->status = -EBUSY;
scb->status = -1;
megaraid_mbox_mm_done(adapter, scb);
return (-EBUSY);
}
return 0;
}
// put the command on the pending list and execute
megaraid_mbox_runpendq(adapter, scb);
return 0;
}
static int
wait_till_fw_empty(adapter_t *adapter)
{
unsigned long flags = 0;
int i;
DECLARE_WAIT_QUEUE_HEAD(wq);
/*
* Set the quiescent flag to stop issuing cmds to FW.
*/
spin_lock_irqsave(adapter->host_lock, flags);
adapter->quiescent++;
spin_unlock_irqrestore(adapter->host_lock, flags);
/*
* Wait till there are no more cmds outstanding at FW. Try for at most
* 60 seconds
*/
for (i = 0; i < 60 && adapter->outstanding_cmds; i++) {
con_log(CL_DLEVEL1, (KERN_INFO
"megaraid: FW has %d pending commands\n",
adapter->outstanding_cmds));
//msleep(1000);
sleep_on_timeout(&wq, HZ);
}
return adapter->outstanding_cmds;
}
/**
* megaraid_mbox_mm_done - callback for CMM commands
* @adapter : HBA soft state
* @scb : completed command
*
* Callback routine for internal commands originated from the management
* module.
*/
static void
megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
{
uioc_t *kioc;
mbox64_t *mbox64;
uint8_t *raw_mbox;
unsigned long flags;
kioc = (uioc_t *)scb->gp;
kioc->status = 0;
mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
mbox64->mbox32.status = scb->status;
raw_mbox = (uint8_t*) &mbox64->mbox32;
// put scb in the free pool
scb->state = SCB_FREE;
scb->scp = NULL;
spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
list_add(&scb->list, &adapter->uscb_pool);
spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
// if a delete logical drive operation succeeded, restart the
// controller
if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
adapter->quiescent--;
megaraid_mbox_runpendq(adapter, 0);
}
kioc->done(kioc);
return;
}
/**
* gather_hbainfo - HBA characteristics for the applications
* @param adapter : HBA soft state
* @param hinfo : pointer to the caller's host info strucuture
*/
static int
gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
{
hinfo->pci_vendor_id = adapter->pdev->vendor;
hinfo->pci_device_id = adapter->pdev->device;
hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor;
hinfo->subsys_device_id = adapter->pdev->subsystem_device;
hinfo->pci_bus = adapter->pdev->bus->number;
hinfo->pci_dev_fn = adapter->pdev->devfn;
hinfo->pci_slot = PCI_SLOT(adapter->pdev->devfn);
hinfo->irq = adapter->host->irq;
hinfo->baseport = ADAP2RAIDDEV(adapter)->baseport;
hinfo->unique_id = (hinfo->pci_bus << 8) | adapter->pdev->devfn;
hinfo->host_no = adapter->host->host_no;
return 0;
}
/*
* END: Interface for the common management module
*/
/*
* END: Mailbox Low Level Driver
*/
module_init(megaraid_init);
module_exit(megaraid_exit);
/* vim: set ts=8 sw=8 tw=78 ai si: */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid.h
*/
#ifndef _MEGARAID_H_
#define _MEGARAID_H_
#include "mega_common.h"
#include "mbox_defs.h"
#include "megaraid_ioctl.h"
#define MEGARAID_VERSION "2.20.0.0"
#define MEGARAID_EXT_VERSION "(Release Date: Wed Jun 23 11:38:38 EDT 2004)"
/*
* Define some PCI values here until they are put in the kernel
*/
#define PCI_DEVICE_ID_PERC4_DI_DISCOVERY 0x000E
#define PCI_SUBSYS_ID_PERC4_DI_DISCOVERY 0x0123
#define PCI_DEVICE_ID_PERC4_SC 0x1960
#define PCI_SUBSYS_ID_PERC4_SC 0x0520
#define PCI_DEVICE_ID_PERC4_DC 0x1960
#define PCI_SUBSYS_ID_PERC4_DC 0x0518
#define PCI_DEVICE_ID_PERC4_QC 0x0407
#define PCI_SUBSYS_ID_PERC4_QC 0x0531
#define PCI_DEVICE_ID_PERC4_DI_EVERGLADES 0x000F
#define PCI_SUBSYS_ID_PERC4_DI_EVERGLADES 0x014A
#define PCI_DEVICE_ID_PERC4E_SI_BIGBEND 0x0013
#define PCI_SUBSYS_ID_PERC4E_SI_BIGBEND 0x016c
#define PCI_DEVICE_ID_PERC4E_DI_KOBUK 0x0013
#define PCI_SUBSYS_ID_PERC4E_DI_KOBUK 0x016d
#define PCI_DEVICE_ID_PERC4E_DI_CORVETTE 0x0013
#define PCI_SUBSYS_ID_PERC4E_DI_CORVETTE 0x016e
#define PCI_DEVICE_ID_PERC4E_DI_EXPEDITION 0x0013
#define PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION 0x016f
#define PCI_DEVICE_ID_PERC4E_DI_GUADALUPE 0x0013
#define PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE 0x0170
#define PCI_DEVICE_ID_PERC4E_DC_320_2E 0x0408
#define PCI_SUBSYS_ID_PERC4E_DC_320_2E 0x0002
#define PCI_DEVICE_ID_PERC4E_SC_320_1E 0x0408
#define PCI_SUBSYS_ID_PERC4E_SC_320_1E 0x0001
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0 0x1960
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0 0xA520
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1 0x1960
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1 0x0520
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2 0x1960
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2 0x0518
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0x 0x0407
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x 0x0530
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2x 0x0407
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x 0x0532
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_4x 0x0407
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x 0x0531
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1E 0x0408
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E 0x0001
#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2E 0x0408
#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E 0x0002
#define PCI_DEVICE_ID_MEGARAID_SATA_150_4 0x1960
#define PCI_SUBSYS_ID_MEGARAID_SATA_150_4 0x4523
#define PCI_DEVICE_ID_MEGARAID_SATA_150_6 0x1960
#define PCI_SUBSYS_ID_MEGARAID_SATA_150_6 0x0523
#define PCI_DEVICE_ID_MEGARAID_SATA_300_4x 0x0409
#define PCI_SUBSYS_ID_MEGARAID_SATA_300_4x 0x3008
#define PCI_DEVICE_ID_MEGARAID_SATA_300_8x 0x0409
#define PCI_SUBSYS_ID_MEGARAID_SATA_300_8x 0x3008
#define PCI_DEVICE_ID_INTEL_RAID_SRCU42X 0x0407
#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42X 0x0532
#define PCI_DEVICE_ID_INTEL_RAID_SRCS16 0x1960
#define PCI_SUBSYS_ID_INTEL_RAID_SRCS16 0x0523
#define PCI_DEVICE_ID_INTEL_RAID_SRCU42E 0x0408
#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42E 0x0002
#define PCI_DEVICE_ID_INTEL_RAID_SRCZCRX 0x0407
#define PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX 0x0530
#define PCI_DEVICE_ID_INTEL_RAID_SRCS28X 0x0409
#define PCI_SUBSYS_ID_INTEL_RAID_SRCS28X 0x3008
#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF 0x0408
#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF 0x3431
#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH 0x0408
#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH 0x3499
#define PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x1960
#define PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x0520
#define PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB 0x0408
#define PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB 0x1065
#define PCI_SUBSYS_ID_PERC3_QC 0x0471
#define PCI_SUBSYS_ID_PERC3_DC 0x0493
#define PCI_SUBSYS_ID_PERC3_SC 0x0475
#ifndef PCI_SUBSYS_ID_FSC
#define PCI_SUBSYS_ID_FSC 0x1734
#endif
#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel
#define MBOX_MAX_USER_CMDS 32 // number of cmds for applications
#define MBOX_DEF_CMD_PER_LUN 64 // default commands per lun
#define MBOX_DEFAULT_SG_SIZE 26 // default sg size supported by all fw
#define MBOX_MAX_SG_SIZE 32 // maximum scatter-gather list size
#define MBOX_MAX_SECTORS 128 // maximum sectors per IO
#define MBOX_TIMEOUT 30 // timeout value for internal cmds
#define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox
#define MBOX_RESET_WAIT 180 // wait these many seconds in reset
#define MBOX_RESET_EXT_WAIT 120 // extended wait reset
/*
* maximum transfer that can happen through the firmware commands issued
* internnaly from the driver.
*/
#define MBOX_IBUF_SIZE 4096
/**
* mbox_ccb_t - command control block specific to mailbox based controllers
* @raw_mbox : raw mailbox pointer
* @mbox : mailbox
* @mbox64 : extended mailbox
* @mbox_dma_h : maibox dma address
* @sgl64 : 64-bit scatter-gather list
* @sgl32 : 32-bit scatter-gather list
* @sgl_dma_h : dma handle for the scatter-gather list
* @pthru : passthru structure
* @pthru_dma_h : dma handle for the passthru structure
* @epthru : extended passthru structure
* @epthru_dma_h : dma handle for extended passthru structure
* @buf_dma_h : dma handle for buffers w/o sg list
*
* command control block specific to the mailbox based controllers
*/
typedef struct {
uint8_t *raw_mbox;
mbox_t *mbox;
mbox64_t *mbox64;
dma_addr_t mbox_dma_h;
mbox_sgl64 *sgl64;
mbox_sgl32 *sgl32;
dma_addr_t sgl_dma_h;
mraid_passthru_t *pthru;
dma_addr_t pthru_dma_h;
mraid_epassthru_t *epthru;
dma_addr_t epthru_dma_h;
dma_addr_t buf_dma_h;
} mbox_ccb_t;
/**
* mraid_device_t - adapter soft state structure for mailbox controllers
* @param una_mbox64 : 64-bit mbox - unaligned
* @param una_mbox64_dma : mbox dma addr - unaligned
* @param mbox : 32-bit mbox - aligned
* @param mbox64 : 64-bit mbox - aligned
* @param mbox_dma : mbox dma addr - aligned
* @param mailbox_lock : exclusion lock for the mailbox
* @param baseport : base port of hba memory
* @param baseaddr : mapped addr of hba memory
* @param mbox_pool : pool of mailboxes
* @param mbox_pool_handle : handle for the mailbox pool memory
* @param epthru_pool : a pool for extended passthru commands
* @param epthru_pool_handle : handle to the pool above
* @param sg_pool : pool of scatter-gather lists for this driver
* @param sg_pool_handle : handle to the pool above
* @param ccb_list : list of our command control blocks
* @param uccb_list : list of cmd control blocks for mgmt module
* @param umbox64 : array of mailbox for user commands (cmm)
* @param pdrv_state : array for state of each physical drive.
* @param last_disp : flag used to show device scanning
* @param hw_error : set if FW not responding
* @param fast_load : If set, skip physical device scanning
* @channel_class : channel class, RAID or SCSI
*
* Initialization structure for mailbox controllers: memory based and IO based
* All the fields in this structure are LLD specific and may be discovered at
* init() or start() time.
*
* NOTE: The fields of this structures are placed to minimize cache misses
*/
typedef struct {
mbox64_t *una_mbox64;
dma_addr_t una_mbox64_dma;
mbox_t *mbox;
mbox64_t *mbox64;
dma_addr_t mbox_dma;
spinlock_t mailbox_lock;
unsigned long baseport;
unsigned long baseaddr;
struct mraid_pci_blk mbox_pool[MBOX_MAX_SCSI_CMDS];
struct dma_pool *mbox_pool_handle;
struct mraid_pci_blk epthru_pool[MBOX_MAX_SCSI_CMDS];
struct dma_pool *epthru_pool_handle;
struct mraid_pci_blk sg_pool[MBOX_MAX_SCSI_CMDS];
struct dma_pool *sg_pool_handle;
mbox_ccb_t ccb_list[MBOX_MAX_SCSI_CMDS];
mbox_ccb_t uccb_list[MBOX_MAX_USER_CMDS];
mbox64_t umbox64[MBOX_MAX_USER_CMDS];
uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES];
uint32_t last_disp;
int hw_error;
int fast_load;
uint8_t channel_class;
} mraid_device_t;
// route to raid device from adapter
#define ADAP2RAIDDEV(adp) ((mraid_device_t *)((adp)->raid_device))
#define MAILBOX_LOCK(rdev) (&(rdev)->mailbox_lock)
// Find out if this channel is a RAID or SCSI
#define IS_RAID_CH(rdev, ch) (((rdev)->channel_class >> (ch)) & 0x01)
#define RDINDOOR(rdev) readl((rdev)->baseaddr + 0x20)
#define RDOUTDOOR(rdev) readl((rdev)->baseaddr + 0x2C)
#define WRINDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x20)
#define WROUTDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x2C)
#endif // _MEGARAID_H_
// vim: set ts=8 sw=8 tw=78:
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mm.c
* Version : v2.20.0.0 (June 23 2004)
*
* Common management module
*/
#include "megaraid_mm.h"
MODULE_AUTHOR("LSI Logic Corporation");
MODULE_DESCRIPTION("LSI Logic Management Module");
MODULE_LICENSE("GPL");
MODULE_VERSION(LSI_COMMON_MOD_VERSION);
static int dbglevel = CL_ANN;
module_param_named(dlevel, dbglevel, int, 0);
MODULE_PARM_DESC(dlevel, "Debug level (default=0)");
EXPORT_SYMBOL(mraid_mm_register_adp);
EXPORT_SYMBOL(mraid_mm_unregister_adp);
static int majorno;
static uint32_t drvr_ver = 0x01000000;
static int slots_inuse = 0;
static mraid_mmadp_t adparr[MAX_LSI_CMN_ADAPS];
wait_queue_head_t wait_q;
static struct file_operations lsi_fops = {
.open = mraid_mm_open,
.ioctl = mraid_mm_ioctl,
.owner = THIS_MODULE,
};
/**
* mraid_mm_open - open routine for char node interface
* @inod : unused
* @filep : unused
*
* allow ioctl operations by apps only if they superuser privilege
*/
static int
mraid_mm_open(struct inode *inode, struct file *filep)
{
/*
* Only allow superuser to access private ioctl interface
*/
if (!capable(CAP_SYS_ADMIN)) return (-EACCES);
return 0;
}
/**
* mraid_mm_ioctl - module entry-point for ioctls
* @inode : inode (ignored)
* @filep : file operations pointer (ignored)
* @cmd : ioctl command
* @arg : user ioctl packet
*/
static int
mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
unsigned long arg)
{
uioc_t *kioc;
char signature[EXT_IOCTL_SIGN_SZ] = {0};
int rval;
mraid_mmadp_t *adp;
int adp_index;
uint8_t old_ioctl;
int drvrcmd_rval;
/*
* Make sure only USCSICMD are issued through this interface.
* MIMD application would still fire different command.
*/
if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) {
return (-EINVAL);
}
/*
* Look for signature to see if this is the new or old ioctl format.
*/
if (copy_from_user(signature, (char *)arg, EXT_IOCTL_SIGN_SZ)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: copy from usr addr failed\n"));
return (-EFAULT);
}
if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0)
old_ioctl = 0;
else
old_ioctl = 1;
/*
* At present, we don't support the new ioctl packet
*/
if (!old_ioctl )
return (-EINVAL);
/*
* If it is a driver ioctl (as opposed to fw ioctls), then we can
* handle the command locally. rval > 0 means it is not a drvr cmd
*/
rval = handle_drvrcmd(arg, old_ioctl, &drvrcmd_rval);
if (rval < 0)
return rval;
else if (rval == 0)
return drvrcmd_rval;
if ((rval = mraid_mm_get_adpindex((mimd_t*)arg, &adp_index))) {
return rval;
}
adp = &adparr[adp_index];
/*
* The following call will block till a kioc is available
*/
kioc = mraid_mm_alloc_kioc(adp);
/*
* User sent the old mimd_t ioctl packet. Convert it to uioc_t.
*/
if ((rval = mimd_to_kioc((mimd_t*)arg, adp, kioc))) {
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
kioc->done = ioctl_done;
/*
* Issue the IOCTL to the low level driver
*/
if ((rval = lld_ioctl(adp, kioc))) {
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
/*
* Convert the kioc back to user space
*/
rval = kioc_to_mimd(kioc, (mimd_t *)arg);
/*
* Return the kioc to free pool
*/
mraid_mm_dealloc_kioc(adp, kioc);
return rval;
}
/**
* mraid_mm_get_adpindex - Returns adp number from mimd_t user packet
* @umimd : User space mimd_t ioctl packet
* @adp_index : Contains adp number if success
*/
static int
mraid_mm_get_adpindex(mimd_t *umimd, int *adp_index)
{
mimd_t mimd;
uint32_t adapno;
*adp_index = -1;
if (copy_from_user( &mimd, umimd, sizeof(mimd_t)))
return (-EFAULT);
adapno = GETADAP(mimd.ui.fcs.adapno);
if (adapno >= slots_inuse)
return (-ENODEV);
*adp_index = adapno;
return 0;
}
/*
* handle_drvrcmd - This routine checks if the opcode is a driver
* cmd and if it is, handles it.
* @arg : packet sent by the user app
* @old_ioctl : mimd if 1; uioc otherwise
*/
static int
handle_drvrcmd(unsigned long arg, uint8_t old_ioctl, int *rval)
{
mimd_t *umimd;
mimd_t kmimd;
uint8_t opcode;
uint8_t subopcode;
if (old_ioctl)
goto old_packet;
else
goto new_packet;
new_packet:
return (-ENOTSUPP);
old_packet:
*rval = 0;
umimd = (mimd_t*) arg;
if (copy_from_user(&kmimd, umimd, sizeof(mimd_t)))
return (-EFAULT);
opcode = kmimd.ui.fcs.opcode;
subopcode = kmimd.ui.fcs.subopcode;
/*
* If the opcode is 0x82 and the subopcode is either GET_DRVRVER or
* GET_NUMADP, then we can handle. Otherwise we should return 1 to
* indicate that we cannot handle this.
*/
if (opcode != 0x82)
return 1;
switch (subopcode) {
case MEGAIOC_QDRVRVER:
if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t)))
return (-EFAULT);
return 0;
case MEGAIOC_QNADAP:
*rval = slots_inuse;
if (copy_to_user(kmimd.data, &slots_inuse, sizeof(uint32_t)))
return (-EFAULT);
return 0;
default:
/* cannot handle */
return 1;
}
return 0;
}
/**
* mimd_to_kioc - Converter from old to new ioctl format
*
* @umimd : user space old MIMD IOCTL
* @kioc : kernel space new format IOCTL
*
* Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The
* new packet is in kernel space so that driver can perform operations on it
* freely.
*/
static int
mimd_to_kioc(mimd_t *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
{
mbox64_t *mbox64;
mraid_passthru_t *pthru32;
uint32_t adapno;
uint8_t opcode;
uint8_t subopcode;
mimd_t mimd;
if (copy_from_user(&mimd, umimd, sizeof(mimd_t)))
return (-EFAULT);
/*
* Applications are not allowed to send extd pthru
*/
if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) ||
(mimd.mbox[0] == MBOXCMD_EXTPTHRU))
return (-EINVAL);
opcode = mimd.ui.fcs.opcode;
subopcode = mimd.ui.fcs.subopcode;
adapno = GETADAP(mimd.ui.fcs.adapno);
if (adapno >= slots_inuse)
return (-ENODEV);
kioc->adapno = adapno;
kioc->mb_type = MBOX_LEGACY;
kioc->app_type = APPTYPE_MIMD;
switch (opcode) {
case 0x82:
if (subopcode == MEGAIOC_QADAPINFO) {
kioc->opcode = GET_ADAP_INFO;
kioc->data_dir = UIOC_RD;
kioc->xferlen = sizeof(mraid_hba_info_t);
if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
return (-ENOMEM);
}
else {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: Invalid subop\n"));
return (-EINVAL);
}
break;
case 0x81:
kioc->opcode = MBOX_CMD;
kioc->xferlen = mimd.ui.fcs.length;
if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
return (-ENOMEM);
if (mimd.outlen) kioc->data_dir = UIOC_RD;
if (mimd.inlen) kioc->data_dir |= UIOC_WR;
break;
case 0x80:
kioc->opcode = MBOX_CMD;
kioc->xferlen = (mimd.outlen > mimd.inlen) ?
mimd.outlen : mimd.inlen;
if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
return (-ENOMEM);
if (mimd.outlen) kioc->data_dir = UIOC_RD;
if (mimd.inlen) kioc->data_dir |= UIOC_WR;
break;
default:
return (-EINVAL);
}
/*
* If driver command, nothing else to do
*/
if (opcode == 0x82)
return 0;
/*
* This is a mailbox cmd; copy the mailbox from mimd
*/
mbox64 = (mbox64_t*)((unsigned long)kioc->cmdbuf);
memcpy(&(mbox64->mbox32), mimd.mbox, 18);
mbox64->xferaddr_lo = mbox64->mbox32.xferaddr;
mbox64->xferaddr_hi = 0;
mbox64->mbox32.xferaddr = 0xffffffff;
if (mbox64->mbox32.cmd != MBOXCMD_PASSTHRU) { // regular DCMD
kioc->user_data = (caddr_t)(unsigned long)
mbox64->xferaddr_lo;
kioc->user_data_len = kioc->xferlen;
mbox64->xferaddr_lo = (unsigned long)kioc->buf_paddr;
if (kioc->data_dir & UIOC_WR) {
if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
kioc->xferlen)) {
return (-EFAULT);
}
}
return 0;
}
/*
* This is a regular 32-bit pthru cmd; mbox points to pthru struct.
* Just like in above case, the beginning for memblk is treated as
* a mailbox. The passthru will begin at next 1K boundary. And the
* data will start 1K after that.
*/
mbox64->mbox32.cmd = MBOXCMD_PASSTHRU;
pthru32 = kioc->pthru32;
kioc->user_pthru = (mraid_passthru_t *)(unsigned long)
mbox64->xferaddr_lo;
mbox64->xferaddr_lo = kioc->pthru32_h;
if (copy_from_user(pthru32, (caddr_t)kioc->user_pthru,
sizeof(mraid_passthru_t))) {
return (-EFAULT);
}
kioc->user_data = (caddr_t)(unsigned long)
pthru32->dataxferaddr;
pthru32->dataxferaddr = kioc->buf_paddr;
kioc->user_data_len = pthru32->dataxferlen;
if (kioc->data_dir & UIOC_WR) {
if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
pthru32->dataxferlen)) {
return (-EFAULT);
}
}
return 0;
}
/**
* mraid_mm_attch_buf - Attach a free dma buffer for required size
*
* @adp : Adapter softstate
* @kioc : kioc that the buffer needs to be attached to
* @xferlen : required length for buffer
*
* First we search for a pool with smallest buffer that is >= @xferlen. If
* that pool has no free buffer, we will try for the next bigger size. If none
* is available, we will try to allocate the smallest buffer that is >=
* @xferlen and attach it the pool.
*/
static int
mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen)
{
mm_dmapool_t *pool;
int right_pool = -1;
unsigned long flags;
int i;
kioc->pool_index = -1;
kioc->buf_vaddr = 0;
kioc->buf_paddr = 0;
kioc->free_buf = 0;
/*
* We need xferlen amount of memory. See if we can get it from our
* dma pools. If we don't get exact size, we will try bigger buffer
*/
for (i = 0; i < MAX_DMA_POOLS; i++) {
pool = &adp->dma_pool_list[i];
if (xferlen > pool->buf_size)
continue;
if (right_pool == -1)
right_pool = i;
spin_lock_irqsave(&pool->lock, flags);
if (!pool->in_use) {
pool->in_use = 1;
kioc->pool_index = i;
kioc->buf_vaddr = pool->vaddr;
kioc->buf_paddr = pool->paddr;
spin_unlock_irqrestore(&pool->lock, flags);
return 0;
}
else {
spin_unlock_irqrestore(&pool->lock, flags);
continue;
}
}
/*
* If xferlen doesn't match any of our pools, return error
*/
if (right_pool == -1)
return -EINVAL;
/*
* We did not get any buffer from the preallocated pool. Let us try
* to allocate one new buffer. NOTE: This is a blocking call.
*/
pool = &adp->dma_pool_list[right_pool];
spin_lock_irqsave(&pool->lock, flags);
kioc->pool_index = right_pool;
kioc->free_buf = 1;
kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL,
&kioc->buf_paddr);
spin_unlock_irqrestore(&pool->lock, flags);
if (!kioc->buf_vaddr)
return -ENOMEM;
return 0;
}
/**
* mraid_mm_alloc_kioc - Returns a uioc_t from free list
* @adp : Adapter softstate for this module
*
* The kioc_semaphore is initialized with number of kioc nodes in the
* free kioc pool. If the kioc pool is empty, this function blocks till
* a kioc becomes free.
*/
static uioc_t *
mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
{
uioc_t *kioc;
struct list_head* head;
unsigned long flags;
down(&adp->kioc_semaphore);
spin_lock_irqsave(&adp->kioc_pool_lock, flags);
head = &adp->kioc_pool;
if (list_empty(head)) {
up(&adp->kioc_semaphore);
spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n"));
return NULL;
}
kioc = list_entry(head->next, uioc_t, list);
list_del_init(&kioc->list);
spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t));
memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t));
kioc->buf_vaddr = 0;
kioc->buf_paddr = 0;
kioc->pool_index =-1;
kioc->free_buf = 0;
kioc->user_data = 0;
kioc->user_data_len = 0;
kioc->user_pthru = 0;
return kioc;
}
/**
* mraid_mm_dealloc_kioc - Return kioc to free pool
*
* @adp : Adapter softstate
* @kioc : uioc_t node to be returned to free pool
*/
static void
mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc)
{
mm_dmapool_t *pool;
unsigned long flags;
pool = &adp->dma_pool_list[kioc->pool_index];
/* This routine may be called in non-isr context also */
spin_lock_irqsave(&pool->lock, flags);
/*
* While attaching the dma buffer, if we didn't get the required
* buffer from the pool, we would have allocated it at the run time
* and set the free_buf flag. We must free that buffer. Otherwise,
* just mark that the buffer is not in use
*/
if (kioc->free_buf == 1)
pci_pool_free(pool->handle, kioc->buf_vaddr, kioc->buf_paddr);
else
pool->in_use = 0;
spin_unlock_irqrestore(&pool->lock, flags);
/* Return the kioc to the free pool */
spin_lock_irqsave(&adp->kioc_pool_lock, flags);
list_add(&kioc->list, &adp->kioc_pool);
spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
/* increment the free kioc count */
up(&adp->kioc_semaphore);
return;
}
/**
* lld_ioctl - Routine to issue ioctl to low level drvr
*
* @adp : The adapter entry in adparr
* @kioc : The ioctl packet with kernel addresses
*/
static int
lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
{
int rval;
struct timer_list timer;
struct timer_list *tp = NULL;
kioc->status = -ENODATA;
rval = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE);
if (rval) return rval;
/*
* Start the timer
*/
if (adp->timeout > 0) {
tp = &timer;
init_timer(tp);
tp->function = lld_timedout;
tp->data = (unsigned long)kioc;
tp->expires = jiffies + adp->timeout * HZ;
add_timer(tp);
}
/*
* Wait till the low level driver completes the ioctl. After this
* call, the ioctl either completed successfully or timedout.
*/
wait_event(wait_q, (kioc->status != -ENODATA));
if (tp) {
del_timer_sync(tp);
}
return kioc->status;
}
/**
* ioctl_done - callback from the low level driver
*
* @kioc : completed ioctl packet
*/
static void
ioctl_done(uioc_t *kioc)
{
/*
* When the kioc returns from driver, make sure it still doesn't
* have ENODATA in status. Otherwise, driver will hang on wait_event
* forever
*/
if (kioc->status == -ENODATA) {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: lld didn't change status!\n"));
kioc->status = -EINVAL;
}
wake_up(&wait_q);
}
/*
* lld_timedout : callback from the expired timer
*
* @ptr : ioctl packet that timed out
*/
static void
lld_timedout(unsigned long ptr)
{
uioc_t *kioc = (uioc_t *)ptr;
kioc->status = -ETIME;
con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n"));
wake_up(&wait_q);
}
/**
* kioc_to_mimd : Converter from new back to old format
*
* @kioc : Kernel space IOCTL packet (successfully issued)
* @mimd : User space MIMD packet
*/
static int
kioc_to_mimd(uioc_t *kioc, mimd_t *mimd)
{
mimd_t kmimd;
uint8_t opcode;
uint8_t subopcode;
mbox64_t *mbox64;
mraid_passthru_t *upthru32;
mraid_passthru_t *kpthru32;
mcontroller_t cinfo;
mraid_hba_info_t *hinfo;
if (copy_from_user( &kmimd, mimd, sizeof(mimd_t)))
return (-EFAULT);
opcode = kmimd.ui.fcs.opcode;
subopcode = kmimd.ui.fcs.subopcode;
if (opcode == 0x82) {
switch (subopcode) {
case MEGAIOC_QADAPINFO:
hinfo = (mraid_hba_info_t*)(unsigned long)
kioc->buf_vaddr;
hinfo_to_cinfo( hinfo, &cinfo );
if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo)))
return (-EFAULT);
return 0;
default:
return (-EINVAL);
}
return 0;
}
mbox64 = (mbox64_t*)(unsigned long)kioc->cmdbuf;
if (kioc->user_pthru) {
upthru32 = kioc->user_pthru;
kpthru32 = kioc->pthru32;
if (copy_to_user((void*)&(upthru32->scsistatus),
(void*)&(kpthru32->scsistatus),
sizeof(uint8_t))) {
return (-EFAULT);
}
}
if (kioc->user_data) {
if (copy_to_user(kioc->user_data, kioc->buf_vaddr,
kioc->user_data_len)) {
return (-EFAULT);
}
}
if (copy_to_user((void*)&mimd->mbox[17], (void*)&mbox64->mbox32.status,
sizeof(uint8_t))) {
return (-EFAULT);
}
return 0;
}
/**
* hinfo_to_cinfo - Convert new format hba info into old format
*
* @hinfo : New format, more comprehensive adapter info
* @cinfo : Old format adapter info to support mimd_t apps
*/
static void
hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo)
{
if (!hinfo || !cinfo)
return;
cinfo->base = hinfo->baseport;
cinfo->irq = hinfo->irq;
cinfo->numldrv = hinfo->num_ldrv;
cinfo->pcibus = hinfo->pci_bus;
cinfo->pcidev = hinfo->pci_slot;
cinfo->pcifun = PCI_FUNC(hinfo->pci_dev_fn);
cinfo->pciid = hinfo->pci_device_id;
cinfo->pcivendor = hinfo->pci_vendor_id;
cinfo->pcislot = hinfo->pci_slot;
cinfo->uid = hinfo->unique_id;
}
/*
* mraid_mm_register_adp - Registration routine for low level drvrs
*
* @adp : Adapter objejct
*/
int
mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
{
mraid_mmadp_t *adapter;
mbox64_t *mbox_list;
uioc_t *kioc;
uint32_t rval;
int i;
if (lld_adp->drvr_type != DRVRTYPE_MBOX)
return (-EINVAL);
adapter = &adparr[slots_inuse];
memset(adapter, 0, sizeof(mraid_mmadp_t));
adapter->unique_id = lld_adp->unique_id;
adapter->drvr_type = lld_adp->drvr_type;
adapter->drvr_data = lld_adp->drvr_data;
adapter->pdev = lld_adp->pdev;
adapter->issue_uioc = lld_adp->issue_uioc;
adapter->timeout = lld_adp->timeout;
adapter->max_kioc = lld_adp->max_kioc;
/*
* Allocate single blocks of memory for all required kiocs,
* mailboxes and passthru structures.
*/
adapter->kioc_list = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc,
GFP_KERNEL);
adapter->mbox_list = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc,
GFP_KERNEL);
adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool",
adapter->pdev,
sizeof(mraid_passthru_t),
16, 0);
if (!adapter->kioc_list || !adapter->mbox_list ||
!adapter->pthru_dma_pool) {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: out of memory, %s %d\n", __FUNCTION__,
__LINE__));
rval = (-ENOMEM);
goto memalloc_error;
}
/*
* Slice kioc_list and make a kioc_pool with the individiual kiocs
*/
INIT_LIST_HEAD(&adapter->kioc_pool);
spin_lock_init(&adapter->kioc_pool_lock);
sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc);
mbox_list = (mbox64_t *)adapter->mbox_list;
for (i = 0; i < lld_adp->max_kioc; i++) {
kioc = adapter->kioc_list + i;
kioc->cmdbuf = (uint64_t)(unsigned long)(mbox_list + i);
kioc->pthru32 = pci_pool_alloc(adapter->pthru_dma_pool,
GFP_KERNEL, &kioc->pthru32_h);
if (!kioc->pthru32) {
con_log(CL_ANN, (KERN_WARNING
"megaraid cmm: out of memory, %s %d\n",
__FUNCTION__, __LINE__));
rval = (-ENOMEM);
goto pthru_dma_pool_error;
}
list_add_tail(&kioc->list, &adapter->kioc_pool);
}
// Setup the dma pools for data buffers
if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) {
goto dma_pool_error;
}
slots_inuse++;
return 0;
dma_pool_error:
/* Do nothing */
pthru_dma_pool_error:
for (i = 0; i < lld_adp->max_kioc; i++) {
kioc = adapter->kioc_list + i;
if (kioc->pthru32) {
pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32,
kioc->pthru32_h);
}
}
memalloc_error:
if (adapter->kioc_list)
kfree(adapter->kioc_list);
if (adapter->mbox_list)
kfree(adapter->mbox_list);
if (adapter->pthru_dma_pool)
pci_pool_destroy(adapter->pthru_dma_pool);
return rval;
}
/**
* mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter
*
* @adp : Adapter softstate
*
* We maintain a pool of dma buffers per each adapter. Each pool has one
* buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers.
* We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We
* dont' want to waste too much memory by allocating more buffers per each
* pool.
*/
static int
mraid_mm_setup_dma_pools(mraid_mmadp_t *adp)
{
mm_dmapool_t *pool;
int bufsize;
int i;
/*
* Create MAX_DMA_POOLS number of pools
*/
bufsize = MRAID_MM_INIT_BUFF_SIZE;
for (i = 0; i < MAX_DMA_POOLS; i++){
pool = &adp->dma_pool_list[i];
pool->buf_size = bufsize;
spin_lock_init(&pool->lock);
pool->handle = pci_pool_create("megaraid mm data buffer",
adp->pdev, bufsize, 16, 0);
if (!pool->handle) {
goto dma_pool_setup_error;
}
pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL,
&pool->paddr);
if (!pool->vaddr)
goto dma_pool_setup_error;
bufsize = bufsize * 2;
}
return 0;
dma_pool_setup_error:
mraid_mm_teardown_dma_pools(adp);
return (-ENOMEM);
}
/*
* mraid_mm_unregister_adp - Unregister routine for low level drivers
* Assume no outstanding ioctls to llds.
*
* @unique_id : UID of the adpater
*/
int
mraid_mm_unregister_adp(uint32_t unique_id)
{
int i;
for (i = 0; i < MAX_LSI_CMN_ADAPS; i++) {
if (adparr[i].unique_id == unique_id) {
mraid_mm_free_adp_resources(&adparr[i]);
memset(&adparr[i], 0, sizeof(mraid_mmadp_t));
con_log(CL_ANN, (
"megaraid cmm: Unregistered one adapter:%#x\n",
unique_id));
return 0;
}
}
return (-ENODEV);
}
/**
* mraid_mm_free_adp_resources - Free adapter softstate
*
* @adp : Adapter softstate
*/
static void
mraid_mm_free_adp_resources(mraid_mmadp_t *adp)
{
uioc_t *kioc;
int i;
INIT_LIST_HEAD(&adp->kioc_pool);
kfree(adp->kioc_list);
kfree(adp->mbox_list);
for (i = 0; i < adp->max_kioc; i++) {
kioc = adp->kioc_list + i;
pci_pool_free(adp->pthru_dma_pool, kioc->pthru32,
kioc->pthru32_h);
}
pci_pool_destroy(adp->pthru_dma_pool);
mraid_mm_teardown_dma_pools(adp);
return;
}
/**
* mraid_mm_teardown_dma_pools - Free all per adapter dma buffers
*
* @adp : Adapter softstate
*/
static void
mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp)
{
int i;
mm_dmapool_t *pool;
for (i = 0; i < MAX_DMA_POOLS; i++) {
pool = &adp->dma_pool_list[i];
if (pool->handle) {
if (pool->vaddr)
pci_pool_free(pool->handle, pool->vaddr,
pool->paddr);
pci_pool_destroy(pool->handle);
pool->handle = 0;
}
}
return;
}
/**
* mraid_mm_init : Module entry point
*/
static int __init
mraid_mm_init(void)
{
// Announce the driver version
con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n",
LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION));
majorno = register_chrdev(0, "megadev", &lsi_fops);
if (majorno < 0) {
con_log(CL_ANN, ("megaraid cmm: cannot get major\n"));
return majorno;
}
init_waitqueue_head(&wait_q);
memset(adparr, 0, sizeof(mraid_mmadp_t) * MAX_LSI_CMN_ADAPS);
slots_inuse = 0;
register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl);
return 0;
}
/**
* mraid_mm_compat_ioctl : 32bit to 64bit ioctl conversion routine
*/
#ifdef LSI_CONFIG_COMPAT
static int
mraid_mm_compat_ioctl(unsigned int fd, unsigned int cmd,
unsigned long arg, struct file *filep)
{
struct inode *inode = filep->f_dentry->d_inode;
return mraid_mm_ioctl(inode, filep, cmd, arg);
}
#endif
/**
* mraid_mm_exit : Module exit point
*/
static void __exit
mraid_mm_exit(void)
{
con_log(CL_DLEVEL1 , ("exiting common mod\n"));
unregister_chrdev(majorno, "megadev");
unregister_ioctl32_conversion(MEGAIOCCMD);
}
module_init(mraid_mm_init);
module_exit(mraid_mm_exit);
/* vi: set ts=8 sw=8 tw=78: */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mm.h
*/
#ifndef MEGARAID_MM_H
#define MEGARAID_MM_H
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/list.h>
#include "mbox_defs.h"
#include "megaraid_ioctl.h"
#define LSI_COMMON_MOD_VERSION "2.20.0.0"
#define LSI_COMMON_MOD_EXT_VERSION \
"(Release Date: Wed Jun 23 11:38:38 EDT 2004)"
#define LSI_DBGLVL dbglevel
// The smallest dma pool
#define MRAID_MM_INIT_BUFF_SIZE 4096
/*
* Localizing ioctl32 differences
*/
#if defined (CONFIG_COMPAT) || defined(__x86_64__) || defined(IA32_EMULATION)
#if !defined(CONFIG_IA64)
#define LSI_CONFIG_COMPAT
#endif
#endif
#ifdef LSI_CONFIG_COMPAT
#include <asm/ioctl32.h>
#else
#define register_ioctl32_conversion(a,b) do{}while(0)
#define unregister_ioctl32_conversion(a) do{}while(0)
#endif /* LSI_CONFIG_COMPAT */
/**
* mimd_t : Old style ioctl packet structure (deprecated)
*
* @inlen :
* @outlen :
* @fca :
* @opcode :
* @subopcode :
* @adapno :
* @buffer :
* @pad :
* @length :
* @mbox :
* @pthru :
* @data :
* @pad :
*
* Note : This structure is DEPRECATED. New applications must use
* : uioc_t structure instead. All new hba drivers use the new
* : format. If we get this mimd packet, we will convert it into
* : new uioc_t format and send it to the hba drivers.
*/
typedef struct mimd {
uint32_t inlen;
uint32_t outlen;
union {
uint8_t fca[16];
struct {
uint8_t opcode;
uint8_t subopcode;
uint16_t adapno;
#if BITS_PER_LONG == 32
uint8_t *buffer;
uint8_t pad[4];
#endif
#if BITS_PER_LONG == 64
uint8_t *buffer;
#endif
uint32_t length;
} __attribute__ ((packed)) fcs;
} __attribute__ ((packed)) ui;
uint8_t mbox[18]; /* 16 bytes + 2 status bytes */
mraid_passthru_t pthru;
#if BITS_PER_LONG == 32
char *data; /* buffer <= 4096 for 0x80 commands */
char pad[4];
#endif
#if BITS_PER_LONG == 64
char *data;
#endif
} __attribute__ ((packed))mimd_t;
// Entry points for char node driver
static int mraid_mm_open(struct inode *, struct file *);
static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long);
// routines to convert to and from the old the format
static int mimd_to_kioc(mimd_t *, mraid_mmadp_t *, uioc_t *);
static int kioc_to_mimd(uioc_t *, mimd_t *);
// Helper functions
static int handle_drvrcmd(unsigned long, uint8_t, int *);
static int lld_ioctl(mraid_mmadp_t *, uioc_t *);
static void ioctl_done(uioc_t *);
static void lld_timedout(unsigned long);
static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *);
static int mraid_mm_get_adpindex(mimd_t *, int *);
static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *);
static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *);
static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int);
static int mraid_mm_setup_dma_pools(mraid_mmadp_t *);
static void mraid_mm_free_adp_resources(mraid_mmadp_t *);
static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *);
#ifdef LSI_CONFIG_COMPAT
static int mraid_mm_compat_ioctl(unsigned int, unsigned int, unsigned long,
struct file *);
#endif
#endif // MEGARAID_MM_H
// vi: set ts=8 sw=8 tw=78:
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment