12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *			Linux MegaRAID device driver
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (c) 2003-2004  LSI Logic Corporation.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * FILE		: megaraid_mbox.c
9cd96d96fSSumant Patro  * Version	: v2.20.5.1 (Nov 16 2006)
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Authors:
12cd96d96fSSumant Patro  * 	Atul Mukker		<Atul.Mukker@lsi.com>
13cd96d96fSSumant Patro  * 	Sreenivas Bagalkote	<Sreenivas.Bagalkote@lsi.com>
14cd96d96fSSumant Patro  * 	Manoj Jose		<Manoj.Jose@lsi.com>
15cd96d96fSSumant Patro  * 	Seokmann Ju
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * List of supported controllers
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  * OEM	Product Name			VID	DID	SSVID	SSID
201da177e4SLinus Torvalds  * ---	------------			---	---	----	----
211da177e4SLinus Torvalds  * Dell PERC3/QC			101E	1960	1028	0471
221da177e4SLinus Torvalds  * Dell PERC3/DC			101E	1960	1028	0493
231da177e4SLinus Torvalds  * Dell PERC3/SC			101E	1960	1028	0475
241da177e4SLinus Torvalds  * Dell PERC3/Di			1028	1960	1028	0123
251da177e4SLinus Torvalds  * Dell PERC4/SC			1000	1960	1028	0520
261da177e4SLinus Torvalds  * Dell PERC4/DC			1000	1960	1028	0518
271da177e4SLinus Torvalds  * Dell PERC4/QC			1000	0407	1028	0531
281da177e4SLinus Torvalds  * Dell PERC4/Di			1028	000F	1028	014A
291da177e4SLinus Torvalds  * Dell PERC 4e/Si			1028	0013	1028	016c
301da177e4SLinus Torvalds  * Dell PERC 4e/Di			1028	0013	1028	016d
311da177e4SLinus Torvalds  * Dell PERC 4e/Di			1028	0013	1028	016e
321da177e4SLinus Torvalds  * Dell PERC 4e/Di			1028	0013	1028	016f
331da177e4SLinus Torvalds  * Dell PERC 4e/Di			1028	0013	1028	0170
341da177e4SLinus Torvalds  * Dell PERC 4e/DC			1000	0408	1028	0002
351da177e4SLinus Torvalds  * Dell PERC 4e/SC			1000	0408	1028	0001
361da177e4SLinus Torvalds  *
371da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-0		1000	1960	1000	A520
381da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-1		1000	1960	1000	0520
391da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-2		1000	1960	1000	0518
401da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-0X		1000	0407	1000	0530
411da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-2X		1000	0407	1000	0532
421da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-4X		1000	0407	1000	0531
431da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-1E		1000	0408	1000	0001
441da177e4SLinus Torvalds  * LSI MegaRAID SCSI 320-2E		1000	0408	1000	0002
451da177e4SLinus Torvalds  * LSI MegaRAID SATA 150-4		1000	1960	1000	4523
461da177e4SLinus Torvalds  * LSI MegaRAID SATA 150-6		1000	1960	1000	0523
471da177e4SLinus Torvalds  * LSI MegaRAID SATA 300-4X		1000	0409	1000	3004
481da177e4SLinus Torvalds  * LSI MegaRAID SATA 300-8X		1000	0409	1000	3008
491da177e4SLinus Torvalds  *
501da177e4SLinus Torvalds  * INTEL RAID Controller SRCU42X	1000	0407	8086	0532
511da177e4SLinus Torvalds  * INTEL RAID Controller SRCS16		1000	1960	8086	0523
521da177e4SLinus Torvalds  * INTEL RAID Controller SRCU42E	1000	0408	8086	0002
531da177e4SLinus Torvalds  * INTEL RAID Controller SRCZCRX	1000	0407	8086	0530
541da177e4SLinus Torvalds  * INTEL RAID Controller SRCS28X	1000	0409	8086	3008
551da177e4SLinus Torvalds  * INTEL RAID Controller SROMBU42E	1000	0408	8086	3431
561da177e4SLinus Torvalds  * INTEL RAID Controller SROMBU42E	1000	0408	8086	3499
571da177e4SLinus Torvalds  * INTEL RAID Controller SRCU51L	1000	1960	8086	0520
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  * FSC	MegaRAID PCI Express ROMB	1000	0408	1734	1065
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  * ACER	MegaRAID ROMB-2E		1000	0408	1025	004D
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  * NEC	MegaRAID PCI Express ROMB	1000	0408	1033	8287
641da177e4SLinus Torvalds  *
65395cf969SPaul Bolle  * For history of changes, see Documentation/scsi/ChangeLog.megaraid
661da177e4SLinus Torvalds  */
671da177e4SLinus Torvalds 
685a0e3ad6STejun Heo #include <linux/slab.h>
69acf3368fSPaul Gortmaker #include <linux/module.h>
701da177e4SLinus Torvalds #include "megaraid_mbox.h"
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds static int megaraid_init(void);
731da177e4SLinus Torvalds static void megaraid_exit(void);
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *);
761da177e4SLinus Torvalds static void megaraid_detach_one(struct pci_dev *);
775457b6a6SRussell King static void megaraid_mbox_shutdown(struct pci_dev *);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds static int megaraid_io_attach(adapter_t *);
801da177e4SLinus Torvalds static void megaraid_io_detach(adapter_t *);
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds static int megaraid_init_mbox(adapter_t *);
831da177e4SLinus Torvalds static void megaraid_fini_mbox(adapter_t *);
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds static int megaraid_alloc_cmd_packets(adapter_t *);
861da177e4SLinus Torvalds static void megaraid_free_cmd_packets(adapter_t *);
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds static int megaraid_mbox_setup_dma_pools(adapter_t *);
891da177e4SLinus Torvalds static void megaraid_mbox_teardown_dma_pools(adapter_t *);
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds static int megaraid_sysfs_alloc_resources(adapter_t *);
921da177e4SLinus Torvalds static void megaraid_sysfs_free_resources(adapter_t *);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds static int megaraid_abort_handler(struct scsi_cmnd *);
951da177e4SLinus Torvalds static int megaraid_reset_handler(struct scsi_cmnd *);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds static int mbox_post_sync_cmd(adapter_t *, uint8_t []);
981da177e4SLinus Torvalds static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []);
991da177e4SLinus Torvalds static int megaraid_busywait_mbox(mraid_device_t *);
1001da177e4SLinus Torvalds static int megaraid_mbox_product_info(adapter_t *);
1011da177e4SLinus Torvalds static int megaraid_mbox_extended_cdb(adapter_t *);
1021da177e4SLinus Torvalds static int megaraid_mbox_support_ha(adapter_t *, uint16_t *);
1031da177e4SLinus Torvalds static int megaraid_mbox_support_random_del(adapter_t *);
1041da177e4SLinus Torvalds static int megaraid_mbox_get_max_sg(adapter_t *);
1051da177e4SLinus Torvalds static void megaraid_mbox_enum_raid_scsi(adapter_t *);
1061da177e4SLinus Torvalds static void megaraid_mbox_flush_cache(adapter_t *);
107cd96d96fSSumant Patro static int megaraid_mbox_fire_sync_cmd(adapter_t *);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
1101da177e4SLinus Torvalds static void megaraid_mbox_setup_device_map(adapter_t *);
1111da177e4SLinus Torvalds 
112f281233dSJeff Garzik static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
1131da177e4SLinus Torvalds static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *);
1141da177e4SLinus Torvalds static void megaraid_mbox_runpendq(adapter_t *, scb_t *);
1151da177e4SLinus Torvalds static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
1161da177e4SLinus Torvalds 		struct scsi_cmnd *);
1171da177e4SLinus Torvalds static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
1181da177e4SLinus Torvalds 		struct scsi_cmnd *);
1191da177e4SLinus Torvalds 
1207d12e780SDavid Howells static irqreturn_t megaraid_isr(int, void *);
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static void megaraid_mbox_dpc(unsigned long);
1231da177e4SLinus Torvalds 
1244c92f898SZhen Lei static ssize_t megaraid_mbox_app_hndl_show(struct device *, struct device_attribute *attr, char *);
1254c92f898SZhen Lei static ssize_t megaraid_mbox_ld_show(struct device *, struct device_attribute *attr, char *);
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds static int megaraid_cmm_register(adapter_t *);
1281da177e4SLinus Torvalds static int megaraid_cmm_unregister(adapter_t *);
1291da177e4SLinus Torvalds static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t);
1301da177e4SLinus Torvalds static int megaraid_mbox_mm_command(adapter_t *, uioc_t *);
1311da177e4SLinus Torvalds static void megaraid_mbox_mm_done(adapter_t *, scb_t *);
1321da177e4SLinus Torvalds static int gather_hbainfo(adapter_t *, mraid_hba_info_t *);
1331da177e4SLinus Torvalds static int wait_till_fw_empty(adapter_t *);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 
137cd96d96fSSumant Patro MODULE_AUTHOR("megaraidlinux@lsi.com");
1381da177e4SLinus Torvalds MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver");
1391da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1401da177e4SLinus Torvalds MODULE_VERSION(MEGARAID_VERSION);
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds /*
1431da177e4SLinus Torvalds  * ### modules parameters for driver ###
1441da177e4SLinus Torvalds  */
1451da177e4SLinus Torvalds 
146a69b74d3SRandy Dunlap /*
1471da177e4SLinus Torvalds  * Set to enable driver to expose unconfigured disk to kernel
1481da177e4SLinus Torvalds  */
1491da177e4SLinus Torvalds static int megaraid_expose_unconf_disks = 0;
1501da177e4SLinus Torvalds module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0);
1511da177e4SLinus Torvalds MODULE_PARM_DESC(unconf_disks,
1521da177e4SLinus Torvalds 	"Set to expose unconfigured disks to kernel (default=0)");
1531da177e4SLinus Torvalds 
154a69b74d3SRandy Dunlap /*
1551da177e4SLinus Torvalds  * driver wait time if the adapter's mailbox is busy
1561da177e4SLinus Torvalds  */
1571da177e4SLinus Torvalds static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT;
1581da177e4SLinus Torvalds module_param_named(busy_wait, max_mbox_busy_wait, int, 0);
1591da177e4SLinus Torvalds MODULE_PARM_DESC(busy_wait,
1601da177e4SLinus Torvalds 	"Max wait for mailbox in microseconds if busy (default=10)");
1611da177e4SLinus Torvalds 
162a69b74d3SRandy Dunlap /*
1631da177e4SLinus Torvalds  * number of sectors per IO command
1641da177e4SLinus Torvalds  */
1651da177e4SLinus Torvalds static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS;
1661da177e4SLinus Torvalds module_param_named(max_sectors, megaraid_max_sectors, int, 0);
1671da177e4SLinus Torvalds MODULE_PARM_DESC(max_sectors,
1681da177e4SLinus Torvalds 	"Maximum number of sectors per IO command (default=128)");
1691da177e4SLinus Torvalds 
170a69b74d3SRandy Dunlap /*
1711da177e4SLinus Torvalds  * number of commands per logical unit
1721da177e4SLinus Torvalds  */
1731da177e4SLinus Torvalds static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN;
1741da177e4SLinus Torvalds module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0);
1751da177e4SLinus Torvalds MODULE_PARM_DESC(cmd_per_lun,
1761da177e4SLinus Torvalds 	"Maximum number of commands per logical unit (default=64)");
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 
179a69b74d3SRandy Dunlap /*
1801da177e4SLinus Torvalds  * Fast driver load option, skip scanning for physical devices during load.
1811da177e4SLinus Torvalds  * This would result in non-disk devices being skipped during driver load
1821da177e4SLinus Torvalds  * time. These can be later added though, using /proc/scsi/scsi
1831da177e4SLinus Torvalds  */
18468126eebSJason Wang static unsigned int megaraid_fast_load;
1851da177e4SLinus Torvalds module_param_named(fast_load, megaraid_fast_load, int, 0);
1861da177e4SLinus Torvalds MODULE_PARM_DESC(fast_load,
1871da177e4SLinus Torvalds 	"Faster loading of the driver, skips physical devices! (default=0)");
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 
190a69b74d3SRandy Dunlap /*
1911da177e4SLinus Torvalds  * mraid_debug level - threshold for amount of information to be displayed by
1921da177e4SLinus Torvalds  * the driver. This level can be changed through modules parameters, ioctl or
1931da177e4SLinus Torvalds  * sysfs/proc interface. By default, print the announcement messages only.
1941da177e4SLinus Torvalds  */
1951da177e4SLinus Torvalds int mraid_debug_level = CL_ANN;
1961da177e4SLinus Torvalds module_param_named(debug_level, mraid_debug_level, int, 0);
1971da177e4SLinus Torvalds MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)");
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds /*
2001da177e4SLinus Torvalds  * PCI table for all supported controllers.
2011da177e4SLinus Torvalds  */
2021da177e4SLinus Torvalds static struct pci_device_id pci_id_table_g[] =  {
2031da177e4SLinus Torvalds 	{
2041da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2051da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4_DI_DISCOVERY,
2061da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2071da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4_DI_DISCOVERY,
2081da177e4SLinus Torvalds 	},
2091da177e4SLinus Torvalds 	{
2101da177e4SLinus Torvalds 		PCI_VENDOR_ID_LSI_LOGIC,
2111da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4_SC,
2121da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2131da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4_SC,
2141da177e4SLinus Torvalds 	},
2151da177e4SLinus Torvalds 	{
2161da177e4SLinus Torvalds 		PCI_VENDOR_ID_LSI_LOGIC,
2171da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4_DC,
2181da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2191da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4_DC,
2201da177e4SLinus Torvalds 	},
2211da177e4SLinus Torvalds 	{
2221da177e4SLinus Torvalds 		PCI_VENDOR_ID_LSI_LOGIC,
223672b2d38SJu, Seokmann  		PCI_DEVICE_ID_VERDE,
224672b2d38SJu, Seokmann  		PCI_ANY_ID,
225672b2d38SJu, Seokmann  		PCI_ANY_ID,
2261da177e4SLinus Torvalds 	},
2271da177e4SLinus Torvalds 	{
2281da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2291da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4_DI_EVERGLADES,
2301da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2311da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4_DI_EVERGLADES,
2321da177e4SLinus Torvalds 	},
2331da177e4SLinus Torvalds 	{
2341da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2351da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4E_SI_BIGBEND,
2361da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2371da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4E_SI_BIGBEND,
2381da177e4SLinus Torvalds 	},
2391da177e4SLinus Torvalds 	{
2401da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2411da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4E_DI_KOBUK,
2421da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2431da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4E_DI_KOBUK,
2441da177e4SLinus Torvalds 	},
2451da177e4SLinus Torvalds 	{
2461da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2471da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4E_DI_CORVETTE,
2481da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2491da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4E_DI_CORVETTE,
2501da177e4SLinus Torvalds 	},
2511da177e4SLinus Torvalds 	{
2521da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2531da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4E_DI_EXPEDITION,
2541da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2551da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION,
2561da177e4SLinus Torvalds 	},
2571da177e4SLinus Torvalds 	{
2581da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2591da177e4SLinus Torvalds 		PCI_DEVICE_ID_PERC4E_DI_GUADALUPE,
2601da177e4SLinus Torvalds 		PCI_VENDOR_ID_DELL,
2611da177e4SLinus Torvalds 		PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE,
2621da177e4SLinus Torvalds 	},
2631da177e4SLinus Torvalds 	{
2641da177e4SLinus Torvalds 		PCI_VENDOR_ID_LSI_LOGIC,
265672b2d38SJu, Seokmann  		PCI_DEVICE_ID_DOBSON,
266672b2d38SJu, Seokmann  		PCI_ANY_ID,
267672b2d38SJu, Seokmann  		PCI_ANY_ID,
2681da177e4SLinus Torvalds 	},
2691da177e4SLinus Torvalds 	{
2701da177e4SLinus Torvalds 		PCI_VENDOR_ID_AMI,
2711da177e4SLinus Torvalds 		PCI_DEVICE_ID_AMI_MEGARAID3,
272ed7e8ef7SJu, Seokmann 		PCI_ANY_ID,
273ed7e8ef7SJu, Seokmann 		PCI_ANY_ID,
2741da177e4SLinus Torvalds 	},
2751da177e4SLinus Torvalds 	{
276ed7e8ef7SJu, Seokmann 		PCI_VENDOR_ID_LSI_LOGIC,
2771da177e4SLinus Torvalds 		PCI_DEVICE_ID_AMI_MEGARAID3,
278ed7e8ef7SJu, Seokmann 		PCI_ANY_ID,
279ed7e8ef7SJu, Seokmann 		PCI_ANY_ID,
2801da177e4SLinus Torvalds 	},
2811da177e4SLinus Torvalds 	{
2821da177e4SLinus Torvalds 		PCI_VENDOR_ID_LSI_LOGIC,
283672b2d38SJu, Seokmann  		PCI_DEVICE_ID_LINDSAY,
284672b2d38SJu, Seokmann  		PCI_ANY_ID,
285672b2d38SJu, Seokmann  		PCI_ANY_ID,
2861da177e4SLinus Torvalds 	},
2871da177e4SLinus Torvalds 	{0}	/* Terminating entry */
2881da177e4SLinus Torvalds };
2891da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, pci_id_table_g);
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 
292382db811SRandy Dunlap static struct pci_driver megaraid_pci_driver = {
2931da177e4SLinus Torvalds 	.name		= "megaraid",
2941da177e4SLinus Torvalds 	.id_table	= pci_id_table_g,
2951da177e4SLinus Torvalds 	.probe		= megaraid_probe_one,
2966f039790SGreg Kroah-Hartman 	.remove		= megaraid_detach_one,
2971da177e4SLinus Torvalds 	.shutdown	= megaraid_mbox_shutdown,
2981da177e4SLinus Torvalds };
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds // definitions for the device attributes for exporting logical drive number
3031da177e4SLinus Torvalds // for a scsi address (Host, Channel, Id, Lun)
3041da177e4SLinus Torvalds 
3054c92f898SZhen Lei static DEVICE_ATTR_ADMIN_RO(megaraid_mbox_app_hndl);
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds // Host template initializer for megaraid mbox sysfs device attributes
308ab53de24SBart Van Assche static struct attribute *megaraid_shost_attrs[] = {
309ab53de24SBart Van Assche 	&dev_attr_megaraid_mbox_app_hndl.attr,
3101da177e4SLinus Torvalds 	NULL,
3111da177e4SLinus Torvalds };
3121da177e4SLinus Torvalds 
313ab53de24SBart Van Assche ATTRIBUTE_GROUPS(megaraid_shost);
3141da177e4SLinus Torvalds 
3154c92f898SZhen Lei static DEVICE_ATTR_ADMIN_RO(megaraid_mbox_ld);
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds // Host template initializer for megaraid mbox sysfs device attributes
318ab53de24SBart Van Assche static struct attribute *megaraid_sdev_attrs[] = {
319ab53de24SBart Van Assche 	&dev_attr_megaraid_mbox_ld.attr,
3201da177e4SLinus Torvalds 	NULL,
3211da177e4SLinus Torvalds };
3221da177e4SLinus Torvalds 
323ab53de24SBart Van Assche ATTRIBUTE_GROUPS(megaraid_sdev);
324ab53de24SBart Van Assche 
3251da177e4SLinus Torvalds /*
3261da177e4SLinus Torvalds  * Scsi host template for megaraid unified driver
3271da177e4SLinus Torvalds  */
328264e222bSBart Van Assche static const struct scsi_host_template megaraid_template_g = {
3291da177e4SLinus Torvalds 	.module				= THIS_MODULE,
3301da177e4SLinus Torvalds 	.name				= "LSI Logic MegaRAID driver",
3311da177e4SLinus Torvalds 	.proc_name			= "megaraid",
3321da177e4SLinus Torvalds 	.queuecommand			= megaraid_queue_command,
3331da177e4SLinus Torvalds 	.eh_abort_handler		= megaraid_abort_handler,
3341da177e4SLinus Torvalds 	.eh_host_reset_handler		= megaraid_reset_handler,
335db5ed4dfSChristoph Hellwig 	.change_queue_depth		= scsi_change_queue_depth,
33654b2b50cSMartin K. Petersen 	.no_write_same			= 1,
337ab53de24SBart Van Assche 	.sdev_groups			= megaraid_sdev_groups,
338ab53de24SBart Van Assche 	.shost_groups			= megaraid_shost_groups,
3391da177e4SLinus Torvalds };
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds /**
3431da177e4SLinus Torvalds  * megaraid_init - module load hook
3441da177e4SLinus Torvalds  *
3451da177e4SLinus Torvalds  * We register ourselves as hotplug enabled module and let PCI subsystem
346a69b74d3SRandy Dunlap  * discover our adapters.
347a69b74d3SRandy Dunlap  */
3481da177e4SLinus Torvalds static int __init
megaraid_init(void)3491da177e4SLinus Torvalds megaraid_init(void)
3501da177e4SLinus Torvalds {
3511da177e4SLinus Torvalds 	int	rval;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	// Announce the driver version
3541da177e4SLinus Torvalds 	con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION,
3551da177e4SLinus Torvalds 		MEGARAID_EXT_VERSION));
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	// check validity of module parameters
3581da177e4SLinus Torvalds 	if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) {
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
3611da177e4SLinus Torvalds 			"megaraid mailbox: max commands per lun reset to %d\n",
3621da177e4SLinus Torvalds 			MBOX_MAX_SCSI_CMDS));
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 		megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS;
3651da177e4SLinus Torvalds 	}
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds 	// register as a PCI hot-plug driver module
369382db811SRandy Dunlap 	rval = pci_register_driver(&megaraid_pci_driver);
370672b2d38SJu, Seokmann  	if (rval < 0) {
3711da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
3721da177e4SLinus Torvalds 			"megaraid: could not register hotplug support.\n"));
3731da177e4SLinus Torvalds 	}
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	return rval;
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds /**
3801da177e4SLinus Torvalds  * megaraid_exit - driver unload entry point
3811da177e4SLinus Torvalds  *
382a69b74d3SRandy Dunlap  * We simply unwrap the megaraid_init routine here.
3831da177e4SLinus Torvalds  */
3841da177e4SLinus Torvalds static void __exit
megaraid_exit(void)3851da177e4SLinus Torvalds megaraid_exit(void)
3861da177e4SLinus Torvalds {
3871da177e4SLinus Torvalds 	con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	// unregister as PCI hotplug driver
390382db811SRandy Dunlap 	pci_unregister_driver(&megaraid_pci_driver);
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	return;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds /**
3971da177e4SLinus Torvalds  * megaraid_probe_one - PCI hotplug entry point
398a69b74d3SRandy Dunlap  * @pdev	: handle to this controller's PCI configuration space
399a69b74d3SRandy Dunlap  * @id		: pci device id of the class of controllers
4001da177e4SLinus Torvalds  *
4011da177e4SLinus Torvalds  * This routine should be called whenever a new adapter is detected by the
4023a4fa0a2SRobert P. J. Day  * PCI hotplug susbsystem.
403a69b74d3SRandy Dunlap  */
4046f039790SGreg Kroah-Hartman static int
megaraid_probe_one(struct pci_dev * pdev,const struct pci_device_id * id)4051da177e4SLinus Torvalds megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
4061da177e4SLinus Torvalds {
4071da177e4SLinus Torvalds 	adapter_t	*adapter;
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 	// detected a new controller
4111da177e4SLinus Torvalds 	con_log(CL_ANN, (KERN_INFO
4121da177e4SLinus Torvalds 		"megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
4131da177e4SLinus Torvalds 		pdev->vendor, pdev->device, pdev->subsystem_vendor,
4141da177e4SLinus Torvalds 		pdev->subsystem_device));
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number,
4171da177e4SLinus Torvalds 		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)));
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	if (pci_enable_device(pdev)) {
4201da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
4211da177e4SLinus Torvalds 				"megaraid: pci_enable_device failed\n"));
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 		return -ENODEV;
4241da177e4SLinus Torvalds 	}
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	// Enable bus-mastering on this controller
4271da177e4SLinus Torvalds 	pci_set_master(pdev);
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	// Allocate the per driver initialization structure
430dd00cc48SYoann Padioleau 	adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 	if (adapter == NULL) {
4331da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
434cadbd4a5SHarvey Harrison 		"megaraid: out of memory, %s %d.\n", __func__, __LINE__));
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 		goto out_probe_one;
4371da177e4SLinus Torvalds 	}
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	// set up PCI related soft state and other pre-known parameters
441*bb1459cbSJialin Zhang 	adapter->unique_id	= pci_dev_id(pdev);
4421da177e4SLinus Torvalds 	adapter->irq		= pdev->irq;
4431da177e4SLinus Torvalds 	adapter->pdev		= pdev;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	atomic_set(&adapter->being_detached, 0);
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds 	// Setup the default DMA mask. This would be changed later on
4481da177e4SLinus Torvalds 	// depending on hardware capabilities
44966e3a241SChristoph Hellwig 	if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(32))) {
4501da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
45166e3a241SChristoph Hellwig 			"megaraid: dma_set_mask failed:%d\n", __LINE__));
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 		goto out_free_adapter;
4541da177e4SLinus Torvalds 	}
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 	// Initialize the synchronization lock for kernel and LLD
4581da177e4SLinus Torvalds 	spin_lock_init(&adapter->lock);
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds 	// Initialize the command queues: the list of free SCBs and the list
4611da177e4SLinus Torvalds 	// of pending SCBs.
4621da177e4SLinus Torvalds 	INIT_LIST_HEAD(&adapter->kscb_pool);
4631da177e4SLinus Torvalds 	spin_lock_init(SCSI_FREE_LIST_LOCK(adapter));
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	INIT_LIST_HEAD(&adapter->pend_list);
4661da177e4SLinus Torvalds 	spin_lock_init(PENDING_LIST_LOCK(adapter));
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	INIT_LIST_HEAD(&adapter->completed_list);
4691da177e4SLinus Torvalds 	spin_lock_init(COMPLETED_LIST_LOCK(adapter));
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	// Start the mailbox based controller
4731da177e4SLinus Torvalds 	if (megaraid_init_mbox(adapter) != 0) {
4741da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
4756868aa76SColin Ian King 			"megaraid: mailbox adapter did not initialize\n"));
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 		goto out_free_adapter;
4781da177e4SLinus Torvalds 	}
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	// Register with LSI Common Management Module
4811da177e4SLinus Torvalds 	if (megaraid_cmm_register(adapter) != 0) {
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
4841da177e4SLinus Torvalds 		"megaraid: could not register with management module\n"));
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds 		goto out_fini_mbox;
4871da177e4SLinus Torvalds 	}
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	// setup adapter handle in PCI soft state
4901da177e4SLinus Torvalds 	pci_set_drvdata(pdev, adapter);
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	// attach with scsi mid-layer
4931da177e4SLinus Torvalds 	if (megaraid_io_attach(adapter) != 0) {
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n"));
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 		goto out_cmm_unreg;
4981da177e4SLinus Torvalds 	}
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds 	return 0;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds out_cmm_unreg:
5031da177e4SLinus Torvalds 	megaraid_cmm_unregister(adapter);
5041da177e4SLinus Torvalds out_fini_mbox:
5051da177e4SLinus Torvalds 	megaraid_fini_mbox(adapter);
5061da177e4SLinus Torvalds out_free_adapter:
5071da177e4SLinus Torvalds 	kfree(adapter);
5081da177e4SLinus Torvalds out_probe_one:
5091da177e4SLinus Torvalds 	pci_disable_device(pdev);
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	return -ENODEV;
5121da177e4SLinus Torvalds }
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds /**
516a69b74d3SRandy Dunlap  * megaraid_detach_one - release framework resources and call LLD release routine
5173948ff8bSMatthias Schid  * @pdev	: handle for our PCI configuration space
5181da177e4SLinus Torvalds  *
5191da177e4SLinus Torvalds  * This routine is called during driver unload. We free all the allocated
5201da177e4SLinus Torvalds  * resources and call the corresponding LLD so that it can also release all
5211da177e4SLinus Torvalds  * its resources.
5221da177e4SLinus Torvalds  *
523a69b74d3SRandy Dunlap  * This routine is also called from the PCI hotplug system.
524a69b74d3SRandy Dunlap  */
5251da177e4SLinus Torvalds static void
megaraid_detach_one(struct pci_dev * pdev)5261da177e4SLinus Torvalds megaraid_detach_one(struct pci_dev *pdev)
5271da177e4SLinus Torvalds {
5281da177e4SLinus Torvalds 	adapter_t		*adapter;
5291da177e4SLinus Torvalds 	struct Scsi_Host	*host;
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	// Start a rollback on this adapter
5331da177e4SLinus Torvalds 	adapter = pci_get_drvdata(pdev);
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	if (!adapter) {
5361da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_CRIT
5371da177e4SLinus Torvalds 		"megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
5381da177e4SLinus Torvalds 			pdev->vendor, pdev->device, pdev->subsystem_vendor,
5391da177e4SLinus Torvalds 			pdev->subsystem_device));
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 		return;
5421da177e4SLinus Torvalds 	}
5431da177e4SLinus Torvalds 	else {
5441da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_NOTICE
5451da177e4SLinus Torvalds 		"megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
5461da177e4SLinus Torvalds 			pdev->vendor, pdev->device, pdev->subsystem_vendor,
5471da177e4SLinus Torvalds 			pdev->subsystem_device));
5481da177e4SLinus Torvalds 	}
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 	host = adapter->host;
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds 	// do not allow any more requests from the management module for this
5541da177e4SLinus Torvalds 	// adapter.
5551da177e4SLinus Torvalds 	// FIXME: How do we account for the request which might still be
5561da177e4SLinus Torvalds 	// pending with us?
5571da177e4SLinus Torvalds 	atomic_set(&adapter->being_detached, 1);
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	// detach from the IO sub-system
5601da177e4SLinus Torvalds 	megaraid_io_detach(adapter);
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	// Unregister from common management module
5631da177e4SLinus Torvalds 	//
5641da177e4SLinus Torvalds 	// FIXME: this must return success or failure for conditions if there
5651da177e4SLinus Torvalds 	// is a command pending with LLD or not.
5661da177e4SLinus Torvalds 	megaraid_cmm_unregister(adapter);
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds 	// finalize the mailbox based controller and release all resources
5691da177e4SLinus Torvalds 	megaraid_fini_mbox(adapter);
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 	kfree(adapter);
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	scsi_host_put(host);
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	pci_disable_device(pdev);
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds 	return;
5781da177e4SLinus Torvalds }
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds /**
5821da177e4SLinus Torvalds  * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA
583a69b74d3SRandy Dunlap  * @pdev		: generic driver model device
5841da177e4SLinus Torvalds  *
585a69b74d3SRandy Dunlap  * Shutdown notification, perform flush cache.
5861da177e4SLinus Torvalds  */
5871da177e4SLinus Torvalds static void
megaraid_mbox_shutdown(struct pci_dev * pdev)5885457b6a6SRussell King megaraid_mbox_shutdown(struct pci_dev *pdev)
5891da177e4SLinus Torvalds {
5905457b6a6SRussell King 	adapter_t		*adapter = pci_get_drvdata(pdev);
5911da177e4SLinus Torvalds 	static int		counter;
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	if (!adapter) {
5941da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
5951da177e4SLinus Torvalds 			"megaraid: null device in shutdown\n"));
5961da177e4SLinus Torvalds 		return;
5971da177e4SLinus Torvalds 	}
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds 	// flush caches now
6001da177e4SLinus Torvalds 	con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...",
6011da177e4SLinus Torvalds 		counter++));
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 	megaraid_mbox_flush_cache(adapter);
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 	con_log(CL_ANN, ("done\n"));
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds /**
6101da177e4SLinus Torvalds  * megaraid_io_attach - attach a device with the IO subsystem
611a69b74d3SRandy Dunlap  * @adapter		: controller's soft state
6121da177e4SLinus Torvalds  *
613a69b74d3SRandy Dunlap  * Attach this device with the IO subsystem.
614a69b74d3SRandy Dunlap  */
6151da177e4SLinus Torvalds static int
megaraid_io_attach(adapter_t * adapter)6161da177e4SLinus Torvalds megaraid_io_attach(adapter_t *adapter)
6171da177e4SLinus Torvalds {
6181da177e4SLinus Torvalds 	struct Scsi_Host	*host;
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	// Initialize SCSI Host structure
6211da177e4SLinus Torvalds 	host = scsi_host_alloc(&megaraid_template_g, 8);
6221da177e4SLinus Torvalds 	if (!host) {
6231da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
6241da177e4SLinus Torvalds 			"megaraid mbox: scsi_register failed\n"));
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 		return -1;
6271da177e4SLinus Torvalds 	}
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	SCSIHOST2ADAP(host)	= (caddr_t)adapter;
6301da177e4SLinus Torvalds 	adapter->host		= host;
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	host->irq		= adapter->irq;
6331da177e4SLinus Torvalds 	host->unique_id		= adapter->unique_id;
6341da177e4SLinus Torvalds 	host->can_queue		= adapter->max_cmds;
6351da177e4SLinus Torvalds 	host->this_id		= adapter->init_id;
6361da177e4SLinus Torvalds 	host->sg_tablesize	= adapter->sglen;
6371da177e4SLinus Torvalds 	host->max_sectors	= adapter->max_sectors;
6381da177e4SLinus Torvalds 	host->cmd_per_lun	= adapter->cmd_per_lun;
6391da177e4SLinus Torvalds 	host->max_channel	= adapter->max_channel;
6401da177e4SLinus Torvalds 	host->max_id		= adapter->max_target;
6411da177e4SLinus Torvalds 	host->max_lun		= adapter->max_lun;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds 	// notify mid-layer about the new controller
6451da177e4SLinus Torvalds 	if (scsi_add_host(host, &adapter->pdev->dev)) {
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
6481da177e4SLinus Torvalds 			"megaraid mbox: scsi_add_host failed\n"));
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 		scsi_host_put(host);
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 		return -1;
6531da177e4SLinus Torvalds 	}
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 	scsi_scan_host(host);
6561da177e4SLinus Torvalds 
6571da177e4SLinus Torvalds 	return 0;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds /**
6621da177e4SLinus Torvalds  * megaraid_io_detach - detach a device from the IO subsystem
663a69b74d3SRandy Dunlap  * @adapter		: controller's soft state
6641da177e4SLinus Torvalds  *
665a69b74d3SRandy Dunlap  * Detach this device from the IO subsystem.
666a69b74d3SRandy Dunlap  */
6671da177e4SLinus Torvalds static void
megaraid_io_detach(adapter_t * adapter)6681da177e4SLinus Torvalds megaraid_io_detach(adapter_t *adapter)
6691da177e4SLinus Torvalds {
6701da177e4SLinus Torvalds 	struct Scsi_Host	*host;
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 	con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n"));
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	host = adapter->host;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	scsi_remove_host(host);
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 	return;
6791da177e4SLinus Torvalds }
6801da177e4SLinus Torvalds 
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds /*
6831da177e4SLinus Torvalds  * START: Mailbox Low Level Driver
6841da177e4SLinus Torvalds  *
6851da177e4SLinus Torvalds  * This is section specific to the single mailbox based controllers
6861da177e4SLinus Torvalds  */
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds /**
6891da177e4SLinus Torvalds  * megaraid_init_mbox - initialize controller
690a69b74d3SRandy Dunlap  * @adapter		: our soft state
6911da177e4SLinus Torvalds  *
692a69b74d3SRandy Dunlap  * - Allocate 16-byte aligned mailbox memory for firmware handshake
693a69b74d3SRandy Dunlap  * - Allocate controller's memory resources
694a69b74d3SRandy Dunlap  * - Find out all initialization data
695a69b74d3SRandy Dunlap  * - Allocate memory required for all the commands
696a69b74d3SRandy Dunlap  * - Use internal library of FW routines, build up complete soft state
6971da177e4SLinus Torvalds  */
6986f039790SGreg Kroah-Hartman static int
megaraid_init_mbox(adapter_t * adapter)6991da177e4SLinus Torvalds megaraid_init_mbox(adapter_t *adapter)
7001da177e4SLinus Torvalds {
7011da177e4SLinus Torvalds 	struct pci_dev		*pdev;
7021da177e4SLinus Torvalds 	mraid_device_t		*raid_dev;
7031da177e4SLinus Torvalds 	int			i;
704fbf60802SJu, Seokmann 	uint32_t		magic64;
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	adapter->ito	= MBOX_TIMEOUT;
7081da177e4SLinus Torvalds 	pdev		= adapter->pdev;
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	/*
7111da177e4SLinus Torvalds 	 * Allocate and initialize the init data structure for mailbox
7121da177e4SLinus Torvalds 	 * controllers
7131da177e4SLinus Torvalds 	 */
714dd00cc48SYoann Padioleau 	raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL);
7151da177e4SLinus Torvalds 	if (raid_dev == NULL) return -1;
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	/*
7191da177e4SLinus Torvalds 	 * Attach the adapter soft state to raid device soft state
7201da177e4SLinus Torvalds 	 */
7211da177e4SLinus Torvalds 	adapter->raid_device	= (caddr_t)raid_dev;
7221da177e4SLinus Torvalds 	raid_dev->fast_load	= megaraid_fast_load;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 	// our baseport
7261da177e4SLinus Torvalds 	raid_dev->baseport = pci_resource_start(pdev, 0);
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) {
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
7311da177e4SLinus Torvalds 				"megaraid: mem region busy\n"));
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 		goto out_free_raid_dev;
7341da177e4SLinus Torvalds 	}
7351da177e4SLinus Torvalds 
7364bdc0d67SChristoph Hellwig 	raid_dev->baseaddr = ioremap(raid_dev->baseport, 128);
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 	if (!raid_dev->baseaddr) {
7391da177e4SLinus Torvalds 
7401da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
7411da177e4SLinus Torvalds 			"megaraid: could not map hba memory\n") );
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 		goto out_release_regions;
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds 
746cd96d96fSSumant Patro 	/* initialize the mutual exclusion lock for the mailbox */
747cd96d96fSSumant Patro 	spin_lock_init(&raid_dev->mailbox_lock);
7481da177e4SLinus Torvalds 
749cd96d96fSSumant Patro 	/* allocate memory required for commands */
750cd96d96fSSumant Patro 	if (megaraid_alloc_cmd_packets(adapter) != 0)
751cd96d96fSSumant Patro 		goto out_iounmap;
752cd96d96fSSumant Patro 
753cd96d96fSSumant Patro 	/*
754cd96d96fSSumant Patro 	 * Issue SYNC cmd to flush the pending cmds in the adapter
755cd96d96fSSumant Patro 	 * and initialize its internal state
756cd96d96fSSumant Patro 	 */
757cd96d96fSSumant Patro 
758cd96d96fSSumant Patro 	if (megaraid_mbox_fire_sync_cmd(adapter))
759cd96d96fSSumant Patro 		con_log(CL_ANN, ("megaraid: sync cmd failed\n"));
760cd96d96fSSumant Patro 
761cd96d96fSSumant Patro 	/*
762cd96d96fSSumant Patro 	 * Setup the rest of the soft state using the library of
763cd96d96fSSumant Patro 	 * FW routines
764cd96d96fSSumant Patro 	 */
765cd96d96fSSumant Patro 
766cd96d96fSSumant Patro 	/* request IRQ and register the interrupt service routine */
7671d6f359aSThomas Gleixner 	if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid",
7681da177e4SLinus Torvalds 		adapter)) {
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
7711da177e4SLinus Torvalds 			"megaraid: Couldn't register IRQ %d!\n", adapter->irq));
772cd96d96fSSumant Patro 		goto out_alloc_cmds;
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds 	}
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 	// Product info
777cd96d96fSSumant Patro 	if (megaraid_mbox_product_info(adapter) != 0)
778cd96d96fSSumant Patro 		goto out_free_irq;
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 	// Do we support extended CDBs
7811da177e4SLinus Torvalds 	adapter->max_cdb_sz = 10;
7821da177e4SLinus Torvalds 	if (megaraid_mbox_extended_cdb(adapter) == 0) {
7831da177e4SLinus Torvalds 		adapter->max_cdb_sz = 16;
7841da177e4SLinus Torvalds 	}
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 	/*
7871da177e4SLinus Torvalds 	 * Do we support cluster environment, if we do, what is the initiator
7881da177e4SLinus Torvalds 	 * id.
7891da177e4SLinus Torvalds 	 * NOTE: In a non-cluster aware firmware environment, the LLD should
7901da177e4SLinus Torvalds 	 * return 7 as initiator id.
7911da177e4SLinus Torvalds 	 */
7921da177e4SLinus Torvalds 	adapter->ha		= 0;
7931da177e4SLinus Torvalds 	adapter->init_id	= -1;
7941da177e4SLinus Torvalds 	if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) {
7951da177e4SLinus Torvalds 		adapter->ha = 1;
7961da177e4SLinus Torvalds 	}
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 	/*
7991da177e4SLinus Torvalds 	 * Prepare the device ids array to have the mapping between the kernel
8001da177e4SLinus Torvalds 	 * device address and megaraid device address.
8011da177e4SLinus Torvalds 	 * We export the physical devices on their actual addresses. The
8021da177e4SLinus Torvalds 	 * logical drives are exported on a virtual SCSI channel
8031da177e4SLinus Torvalds 	 */
8041da177e4SLinus Torvalds 	megaraid_mbox_setup_device_map(adapter);
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds 	// If the firmware supports random deletion, update the device id map
8071da177e4SLinus Torvalds 	if (megaraid_mbox_support_random_del(adapter)) {
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds 		// Change the logical drives numbers in device_ids array one
8101da177e4SLinus Torvalds 		// slot in device_ids is reserved for target id, that's why
8111da177e4SLinus Torvalds 		// "<=" below
8121da177e4SLinus Torvalds 		for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) {
8131da177e4SLinus Torvalds 			adapter->device_ids[adapter->max_channel][i] += 0x80;
8141da177e4SLinus Torvalds 		}
8151da177e4SLinus Torvalds 		adapter->device_ids[adapter->max_channel][adapter->init_id] =
8161da177e4SLinus Torvalds 			0xFF;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 		raid_dev->random_del_supported = 1;
8191da177e4SLinus Torvalds 	}
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	/*
8221da177e4SLinus Torvalds 	 * find out the maximum number of scatter-gather elements supported by
8231da177e4SLinus Torvalds 	 * this firmware
8241da177e4SLinus Torvalds 	 */
8251da177e4SLinus Torvalds 	adapter->sglen = megaraid_mbox_get_max_sg(adapter);
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 	// enumerate RAID and SCSI channels so that all devices on SCSI
8281da177e4SLinus Torvalds 	// channels can later be exported, including disk devices
8291da177e4SLinus Torvalds 	megaraid_mbox_enum_raid_scsi(adapter);
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds 	/*
8321da177e4SLinus Torvalds 	 * Other parameters required by upper layer
8331da177e4SLinus Torvalds 	 *
8341da177e4SLinus Torvalds 	 * maximum number of sectors per IO command
8351da177e4SLinus Torvalds 	 */
8361da177e4SLinus Torvalds 	adapter->max_sectors = megaraid_max_sectors;
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 	/*
8391da177e4SLinus Torvalds 	 * number of queued commands per LUN.
8401da177e4SLinus Torvalds 	 */
8411da177e4SLinus Torvalds 	adapter->cmd_per_lun = megaraid_cmd_per_lun;
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 	/*
8441da177e4SLinus Torvalds 	 * Allocate resources required to issue FW calls, when sysfs is
8451da177e4SLinus Torvalds 	 * accessed
8461da177e4SLinus Torvalds 	 */
847cd96d96fSSumant Patro 	if (megaraid_sysfs_alloc_resources(adapter) != 0)
848cd96d96fSSumant Patro 		goto out_free_irq;
8491da177e4SLinus Torvalds 
8501da177e4SLinus Torvalds 	// Set the DMA mask to 64-bit. All supported controllers as capable of
8511da177e4SLinus Torvalds 	// DMA in this range
852fbf60802SJu, Seokmann 	pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64);
8531da177e4SLinus Torvalds 
854fbf60802SJu, Seokmann 	if (((magic64 == HBA_SIGNATURE_64_BIT) &&
855fbf60802SJu, Seokmann 		((adapter->pdev->subsystem_device !=
8568741ca71SAndrey Mirkin 		PCI_SUBSYS_ID_MEGARAID_SATA_150_6) &&
857fbf60802SJu, Seokmann 		(adapter->pdev->subsystem_device !=
858fbf60802SJu, Seokmann 		PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) ||
859fbf60802SJu, Seokmann 		(adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
860fbf60802SJu, Seokmann 		adapter->pdev->device == PCI_DEVICE_ID_VERDE) ||
861fbf60802SJu, Seokmann 		(adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
862fbf60802SJu, Seokmann 		adapter->pdev->device == PCI_DEVICE_ID_DOBSON) ||
863fbf60802SJu, Seokmann 		(adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
864fbf60802SJu, Seokmann 		adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) ||
865fbf60802SJu, Seokmann 		(adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
866fbf60802SJu, Seokmann 		adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) ||
867fbf60802SJu, Seokmann 		(adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
868fbf60802SJu, Seokmann 		adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) {
86966e3a241SChristoph Hellwig 		if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(64))) {
8701da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_WARNING
871fbf60802SJu, Seokmann 				"megaraid: DMA mask for 64-bit failed\n"));
8721da177e4SLinus Torvalds 
87366e3a241SChristoph Hellwig 			if (dma_set_mask(&adapter->pdev->dev,
87466e3a241SChristoph Hellwig 						DMA_BIT_MASK(32))) {
875fbf60802SJu, Seokmann 				con_log(CL_ANN, (KERN_WARNING
876fbf60802SJu, Seokmann 					"megaraid: 32-bit DMA mask failed\n"));
8771da177e4SLinus Torvalds 				goto out_free_sysfs_res;
8781da177e4SLinus Torvalds 			}
879fbf60802SJu, Seokmann 		}
880fbf60802SJu, Seokmann 	}
8811da177e4SLinus Torvalds 
8821da177e4SLinus Torvalds 	// setup tasklet for DPC
8831da177e4SLinus Torvalds 	tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc,
8841da177e4SLinus Torvalds 			(unsigned long)adapter);
8851da177e4SLinus Torvalds 
8861da177e4SLinus Torvalds 	con_log(CL_DLEVEL1, (KERN_INFO
8871da177e4SLinus Torvalds 		"megaraid mbox hba successfully initialized\n"));
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	return 0;
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds out_free_sysfs_res:
8921da177e4SLinus Torvalds 	megaraid_sysfs_free_resources(adapter);
8931da177e4SLinus Torvalds out_free_irq:
8941da177e4SLinus Torvalds 	free_irq(adapter->irq, adapter);
895cd96d96fSSumant Patro out_alloc_cmds:
896cd96d96fSSumant Patro 	megaraid_free_cmd_packets(adapter);
8971da177e4SLinus Torvalds out_iounmap:
8981da177e4SLinus Torvalds 	iounmap(raid_dev->baseaddr);
8991da177e4SLinus Torvalds out_release_regions:
9001da177e4SLinus Torvalds 	pci_release_regions(pdev);
9011da177e4SLinus Torvalds out_free_raid_dev:
9021da177e4SLinus Torvalds 	kfree(raid_dev);
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	return -1;
9051da177e4SLinus Torvalds }
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds /**
9091da177e4SLinus Torvalds  * megaraid_fini_mbox - undo controller initialization
910a69b74d3SRandy Dunlap  * @adapter		: our soft state
9111da177e4SLinus Torvalds  */
9121da177e4SLinus Torvalds static void
megaraid_fini_mbox(adapter_t * adapter)9131da177e4SLinus Torvalds megaraid_fini_mbox(adapter_t *adapter)
9141da177e4SLinus Torvalds {
9151da177e4SLinus Torvalds 	mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds 	// flush all caches
9181da177e4SLinus Torvalds 	megaraid_mbox_flush_cache(adapter);
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	tasklet_kill(&adapter->dpc_h);
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds 	megaraid_sysfs_free_resources(adapter);
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds 	megaraid_free_cmd_packets(adapter);
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 	free_irq(adapter->irq, adapter);
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds 	iounmap(raid_dev->baseaddr);
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	pci_release_regions(adapter->pdev);
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	kfree(raid_dev);
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 	return;
9351da177e4SLinus Torvalds }
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds 
9381da177e4SLinus Torvalds /**
9391da177e4SLinus Torvalds  * megaraid_alloc_cmd_packets - allocate shared mailbox
940a69b74d3SRandy Dunlap  * @adapter		: soft state of the raid controller
9411da177e4SLinus Torvalds  *
9426868aa76SColin Ian King  * Allocate and align the shared mailbox. This mailbox is used to issue
9433948ff8bSMatthias Schid  * all the commands. For IO based controllers, the mailbox is also registered
9441da177e4SLinus Torvalds  * with the FW. Allocate memory for all commands as well.
945a69b74d3SRandy Dunlap  * This is our big allocator.
9461da177e4SLinus Torvalds  */
9471da177e4SLinus Torvalds static int
megaraid_alloc_cmd_packets(adapter_t * adapter)9481da177e4SLinus Torvalds megaraid_alloc_cmd_packets(adapter_t *adapter)
9491da177e4SLinus Torvalds {
9501da177e4SLinus Torvalds 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
9511da177e4SLinus Torvalds 	struct pci_dev		*pdev;
9521da177e4SLinus Torvalds 	unsigned long		align;
9531da177e4SLinus Torvalds 	scb_t			*scb;
9541da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
9551da177e4SLinus Torvalds 	struct mraid_pci_blk	*epthru_pci_blk;
9561da177e4SLinus Torvalds 	struct mraid_pci_blk	*sg_pci_blk;
9571da177e4SLinus Torvalds 	struct mraid_pci_blk	*mbox_pci_blk;
9581da177e4SLinus Torvalds 	int			i;
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds 	pdev = adapter->pdev;
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds 	/*
9631da177e4SLinus Torvalds 	 * Setup the mailbox
9641da177e4SLinus Torvalds 	 * Allocate the common 16-byte aligned memory for the handshake
9651da177e4SLinus Torvalds 	 * mailbox.
9661da177e4SLinus Torvalds 	 */
967750afb08SLuis Chamberlain 	raid_dev->una_mbox64 = dma_alloc_coherent(&adapter->pdev->dev,
968750afb08SLuis Chamberlain 						  sizeof(mbox64_t),
969750afb08SLuis Chamberlain 						  &raid_dev->una_mbox64_dma,
97066e3a241SChristoph Hellwig 						  GFP_KERNEL);
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	if (!raid_dev->una_mbox64) {
9731da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
974cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
9751da177e4SLinus Torvalds 			__LINE__));
9761da177e4SLinus Torvalds 		return -1;
9771da177e4SLinus Torvalds 	}
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 	/*
9801da177e4SLinus Torvalds 	 * Align the mailbox at 16-byte boundary
9811da177e4SLinus Torvalds 	 */
9821da177e4SLinus Torvalds 	raid_dev->mbox	= &raid_dev->una_mbox64->mbox32;
9831da177e4SLinus Torvalds 
9841da177e4SLinus Torvalds 	raid_dev->mbox	= (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) &
9851da177e4SLinus Torvalds 				(~0UL ^ 0xFUL));
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds 	raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8);
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds 	align = ((void *)raid_dev->mbox -
9901da177e4SLinus Torvalds 			((void *)&raid_dev->una_mbox64->mbox32));
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 	raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 +
9931da177e4SLinus Torvalds 			align;
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 	// Allocate memory for commands issued internally
996750afb08SLuis Chamberlain 	adapter->ibuf = dma_alloc_coherent(&pdev->dev, MBOX_IBUF_SIZE,
99766e3a241SChristoph Hellwig 					   &adapter->ibuf_dma_h, GFP_KERNEL);
9981da177e4SLinus Torvalds 	if (!adapter->ibuf) {
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
1001cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
10021da177e4SLinus Torvalds 			__LINE__));
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 		goto out_free_common_mbox;
10051da177e4SLinus Torvalds 	}
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds 	// Allocate memory for our SCSI Command Blocks and their associated
10081da177e4SLinus Torvalds 	// memory
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 	/*
10111da177e4SLinus Torvalds 	 * Allocate memory for the base list of scb. Later allocate memory for
10121da177e4SLinus Torvalds 	 * CCBs and embedded components of each CCB and point the pointers in
10131da177e4SLinus Torvalds 	 * scb to the allocated components
10141da177e4SLinus Torvalds 	 * NOTE: The code to allocate SCB will be duplicated in all the LLD
10151da177e4SLinus Torvalds 	 * since the calling routine does not yet know the number of available
10161da177e4SLinus Torvalds 	 * commands.
10171da177e4SLinus Torvalds 	 */
1018dd00cc48SYoann Padioleau 	adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL);
10191da177e4SLinus Torvalds 
10201da177e4SLinus Torvalds 	if (adapter->kscb_list == NULL) {
10211da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
1022cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
10231da177e4SLinus Torvalds 			__LINE__));
10241da177e4SLinus Torvalds 		goto out_free_ibuf;
10251da177e4SLinus Torvalds 	}
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 	// memory allocation for our command packets
10281da177e4SLinus Torvalds 	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
10291da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
1030cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
10311da177e4SLinus Torvalds 			__LINE__));
10321da177e4SLinus Torvalds 		goto out_free_scb_list;
10331da177e4SLinus Torvalds 	}
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds 	// Adjust the scb pointers and link in the free pool
10361da177e4SLinus Torvalds 	epthru_pci_blk	= raid_dev->epthru_pool;
10371da177e4SLinus Torvalds 	sg_pci_blk	= raid_dev->sg_pool;
10381da177e4SLinus Torvalds 	mbox_pci_blk	= raid_dev->mbox_pool;
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
10411da177e4SLinus Torvalds 		scb			= adapter->kscb_list + i;
10421da177e4SLinus Torvalds 		ccb			= raid_dev->ccb_list + i;
10431da177e4SLinus Torvalds 
10441da177e4SLinus Torvalds 		ccb->mbox	= (mbox_t *)(mbox_pci_blk[i].vaddr + 16);
10451da177e4SLinus Torvalds 		ccb->raw_mbox	= (uint8_t *)ccb->mbox;
10461da177e4SLinus Torvalds 		ccb->mbox64	= (mbox64_t *)(mbox_pci_blk[i].vaddr + 8);
10471da177e4SLinus Torvalds 		ccb->mbox_dma_h	= (unsigned long)mbox_pci_blk[i].dma_addr + 16;
10481da177e4SLinus Torvalds 
10491da177e4SLinus Torvalds 		// make sure the mailbox is aligned properly
10501da177e4SLinus Torvalds 		if (ccb->mbox_dma_h & 0x0F) {
10511da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_CRIT
10521da177e4SLinus Torvalds 				"megaraid mbox: not aligned on 16-bytes\n"));
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 			goto out_teardown_dma_pools;
10551da177e4SLinus Torvalds 		}
10561da177e4SLinus Torvalds 
10571da177e4SLinus Torvalds 		ccb->epthru		= (mraid_epassthru_t *)
10581da177e4SLinus Torvalds 						epthru_pci_blk[i].vaddr;
10591da177e4SLinus Torvalds 		ccb->epthru_dma_h	= epthru_pci_blk[i].dma_addr;
10601da177e4SLinus Torvalds 		ccb->pthru		= (mraid_passthru_t *)ccb->epthru;
10611da177e4SLinus Torvalds 		ccb->pthru_dma_h	= ccb->epthru_dma_h;
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 		ccb->sgl64		= (mbox_sgl64 *)sg_pci_blk[i].vaddr;
10651da177e4SLinus Torvalds 		ccb->sgl_dma_h		= sg_pci_blk[i].dma_addr;
10661da177e4SLinus Torvalds 		ccb->sgl32		= (mbox_sgl32 *)ccb->sgl64;
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds 		scb->ccb		= (caddr_t)ccb;
10691da177e4SLinus Torvalds 		scb->gp			= 0;
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds 		scb->sno		= i;	// command index
10721da177e4SLinus Torvalds 
10731da177e4SLinus Torvalds 		scb->scp		= NULL;
10741da177e4SLinus Torvalds 		scb->state		= SCB_FREE;
107566e3a241SChristoph Hellwig 		scb->dma_direction	= DMA_NONE;
10761da177e4SLinus Torvalds 		scb->dma_type		= MRAID_DMA_NONE;
10771da177e4SLinus Torvalds 		scb->dev_channel	= -1;
10781da177e4SLinus Torvalds 		scb->dev_target		= -1;
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds 		// put scb in the free pool
10811da177e4SLinus Torvalds 		list_add_tail(&scb->list, &adapter->kscb_pool);
10821da177e4SLinus Torvalds 	}
10831da177e4SLinus Torvalds 
10841da177e4SLinus Torvalds 	return 0;
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds out_teardown_dma_pools:
10871da177e4SLinus Torvalds 	megaraid_mbox_teardown_dma_pools(adapter);
10881da177e4SLinus Torvalds out_free_scb_list:
10891da177e4SLinus Torvalds 	kfree(adapter->kscb_list);
10901da177e4SLinus Torvalds out_free_ibuf:
109166e3a241SChristoph Hellwig 	dma_free_coherent(&pdev->dev, MBOX_IBUF_SIZE, (void *)adapter->ibuf,
10921da177e4SLinus Torvalds 		adapter->ibuf_dma_h);
10931da177e4SLinus Torvalds out_free_common_mbox:
109466e3a241SChristoph Hellwig 	dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t),
10951da177e4SLinus Torvalds 		(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 	return -1;
10981da177e4SLinus Torvalds }
10991da177e4SLinus Torvalds 
11001da177e4SLinus Torvalds 
11011da177e4SLinus Torvalds /**
11021da177e4SLinus Torvalds  * megaraid_free_cmd_packets - free memory
1103a69b74d3SRandy Dunlap  * @adapter		: soft state of the raid controller
11041da177e4SLinus Torvalds  *
1105a69b74d3SRandy Dunlap  * Release memory resources allocated for commands.
11061da177e4SLinus Torvalds  */
11071da177e4SLinus Torvalds static void
megaraid_free_cmd_packets(adapter_t * adapter)11081da177e4SLinus Torvalds megaraid_free_cmd_packets(adapter_t *adapter)
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds 	mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	megaraid_mbox_teardown_dma_pools(adapter);
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	kfree(adapter->kscb_list);
11151da177e4SLinus Torvalds 
111666e3a241SChristoph Hellwig 	dma_free_coherent(&adapter->pdev->dev, MBOX_IBUF_SIZE,
11171da177e4SLinus Torvalds 		(void *)adapter->ibuf, adapter->ibuf_dma_h);
11181da177e4SLinus Torvalds 
111966e3a241SChristoph Hellwig 	dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t),
11201da177e4SLinus Torvalds 		(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
11211da177e4SLinus Torvalds 	return;
11221da177e4SLinus Torvalds }
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds /**
11261da177e4SLinus Torvalds  * megaraid_mbox_setup_dma_pools - setup dma pool for command packets
1127a69b74d3SRandy Dunlap  * @adapter		: HBA soft state
11281da177e4SLinus Torvalds  *
1129a69b74d3SRandy Dunlap  * Setup the dma pools for mailbox, passthru and extended passthru structures,
1130a69b74d3SRandy Dunlap  * and scatter-gather lists.
11311da177e4SLinus Torvalds  */
11321da177e4SLinus Torvalds static int
megaraid_mbox_setup_dma_pools(adapter_t * adapter)11331da177e4SLinus Torvalds megaraid_mbox_setup_dma_pools(adapter_t *adapter)
11341da177e4SLinus Torvalds {
11351da177e4SLinus Torvalds 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
11361da177e4SLinus Torvalds 	struct mraid_pci_blk	*epthru_pci_blk;
11371da177e4SLinus Torvalds 	struct mraid_pci_blk	*sg_pci_blk;
11381da177e4SLinus Torvalds 	struct mraid_pci_blk	*mbox_pci_blk;
11391da177e4SLinus Torvalds 	int			i;
11401da177e4SLinus Torvalds 
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	// Allocate memory for 16-bytes aligned mailboxes
1144fc69d86dSRomain Perier 	raid_dev->mbox_pool_handle = dma_pool_create("megaraid mbox pool",
1145fc69d86dSRomain Perier 						&adapter->pdev->dev,
11461da177e4SLinus Torvalds 						sizeof(mbox64_t) + 16,
11471da177e4SLinus Torvalds 						16, 0);
11481da177e4SLinus Torvalds 
11491da177e4SLinus Torvalds 	if (raid_dev->mbox_pool_handle == NULL) {
11501da177e4SLinus Torvalds 		goto fail_setup_dma_pool;
11511da177e4SLinus Torvalds 	}
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 	mbox_pci_blk = raid_dev->mbox_pool;
11541da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
1155fc69d86dSRomain Perier 		mbox_pci_blk[i].vaddr = dma_pool_alloc(
11561da177e4SLinus Torvalds 						raid_dev->mbox_pool_handle,
11571da177e4SLinus Torvalds 						GFP_KERNEL,
11581da177e4SLinus Torvalds 						&mbox_pci_blk[i].dma_addr);
11591da177e4SLinus Torvalds 		if (!mbox_pci_blk[i].vaddr) {
11601da177e4SLinus Torvalds 			goto fail_setup_dma_pool;
11611da177e4SLinus Torvalds 		}
11621da177e4SLinus Torvalds 	}
11631da177e4SLinus Torvalds 
11641da177e4SLinus Torvalds 	/*
11651da177e4SLinus Torvalds 	 * Allocate memory for each embedded passthru strucuture pointer
11661da177e4SLinus Torvalds 	 * Request for a 128 bytes aligned structure for each passthru command
11671da177e4SLinus Torvalds 	 * structure
11681da177e4SLinus Torvalds 	 * Since passthru and extended passthru commands are exclusive, they
11691da177e4SLinus Torvalds 	 * share common memory pool. Passthru structures piggyback on memory
117083e4a9b3Sdingsenjie 	 * allocated to extended passthru since passthru is smaller of the two
11711da177e4SLinus Torvalds 	 */
1172fc69d86dSRomain Perier 	raid_dev->epthru_pool_handle = dma_pool_create("megaraid mbox pthru",
1173fc69d86dSRomain Perier 			&adapter->pdev->dev, sizeof(mraid_epassthru_t), 128, 0);
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 	if (raid_dev->epthru_pool_handle == NULL) {
11761da177e4SLinus Torvalds 		goto fail_setup_dma_pool;
11771da177e4SLinus Torvalds 	}
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 	epthru_pci_blk = raid_dev->epthru_pool;
11801da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
1181fc69d86dSRomain Perier 		epthru_pci_blk[i].vaddr = dma_pool_alloc(
11821da177e4SLinus Torvalds 						raid_dev->epthru_pool_handle,
11831da177e4SLinus Torvalds 						GFP_KERNEL,
11841da177e4SLinus Torvalds 						&epthru_pci_blk[i].dma_addr);
11851da177e4SLinus Torvalds 		if (!epthru_pci_blk[i].vaddr) {
11861da177e4SLinus Torvalds 			goto fail_setup_dma_pool;
11871da177e4SLinus Torvalds 		}
11881da177e4SLinus Torvalds 	}
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds 
11911da177e4SLinus Torvalds 	// Allocate memory for each scatter-gather list. Request for 512 bytes
11921da177e4SLinus Torvalds 	// alignment for each sg list
1193fc69d86dSRomain Perier 	raid_dev->sg_pool_handle = dma_pool_create("megaraid mbox sg",
1194fc69d86dSRomain Perier 					&adapter->pdev->dev,
11951da177e4SLinus Torvalds 					sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE,
11961da177e4SLinus Torvalds 					512, 0);
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	if (raid_dev->sg_pool_handle == NULL) {
11991da177e4SLinus Torvalds 		goto fail_setup_dma_pool;
12001da177e4SLinus Torvalds 	}
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds 	sg_pci_blk = raid_dev->sg_pool;
12031da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
1204fc69d86dSRomain Perier 		sg_pci_blk[i].vaddr = dma_pool_alloc(
12051da177e4SLinus Torvalds 						raid_dev->sg_pool_handle,
12061da177e4SLinus Torvalds 						GFP_KERNEL,
12071da177e4SLinus Torvalds 						&sg_pci_blk[i].dma_addr);
12081da177e4SLinus Torvalds 		if (!sg_pci_blk[i].vaddr) {
12091da177e4SLinus Torvalds 			goto fail_setup_dma_pool;
12101da177e4SLinus Torvalds 		}
12111da177e4SLinus Torvalds 	}
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 	return 0;
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds fail_setup_dma_pool:
12161da177e4SLinus Torvalds 	megaraid_mbox_teardown_dma_pools(adapter);
12171da177e4SLinus Torvalds 	return -1;
12181da177e4SLinus Torvalds }
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds /**
12221da177e4SLinus Torvalds  * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets
1223a69b74d3SRandy Dunlap  * @adapter		: HBA soft state
12241da177e4SLinus Torvalds  *
1225a69b74d3SRandy Dunlap  * Teardown the dma pool for mailbox, passthru and extended passthru
1226a69b74d3SRandy Dunlap  * structures, and scatter-gather lists.
12271da177e4SLinus Torvalds  */
12281da177e4SLinus Torvalds static void
megaraid_mbox_teardown_dma_pools(adapter_t * adapter)12291da177e4SLinus Torvalds megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
12301da177e4SLinus Torvalds {
12311da177e4SLinus Torvalds 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
12321da177e4SLinus Torvalds 	struct mraid_pci_blk	*epthru_pci_blk;
12331da177e4SLinus Torvalds 	struct mraid_pci_blk	*sg_pci_blk;
12341da177e4SLinus Torvalds 	struct mraid_pci_blk	*mbox_pci_blk;
12351da177e4SLinus Torvalds 	int			i;
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds 	sg_pci_blk = raid_dev->sg_pool;
12391da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) {
1240fc69d86dSRomain Perier 		dma_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr,
12411da177e4SLinus Torvalds 			sg_pci_blk[i].dma_addr);
12421da177e4SLinus Torvalds 	}
1243fc69d86dSRomain Perier 	dma_pool_destroy(raid_dev->sg_pool_handle);
12441da177e4SLinus Torvalds 
12451da177e4SLinus Torvalds 
12461da177e4SLinus Torvalds 	epthru_pci_blk = raid_dev->epthru_pool;
12471da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) {
1248fc69d86dSRomain Perier 		dma_pool_free(raid_dev->epthru_pool_handle,
12491da177e4SLinus Torvalds 			epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr);
12501da177e4SLinus Torvalds 	}
1251fc69d86dSRomain Perier 	dma_pool_destroy(raid_dev->epthru_pool_handle);
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 	mbox_pci_blk = raid_dev->mbox_pool;
12551da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) {
1256fc69d86dSRomain Perier 		dma_pool_free(raid_dev->mbox_pool_handle,
12571da177e4SLinus Torvalds 			mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr);
12581da177e4SLinus Torvalds 	}
1259fc69d86dSRomain Perier 	dma_pool_destroy(raid_dev->mbox_pool_handle);
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds 	return;
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 
12651da177e4SLinus Torvalds /**
12661da177e4SLinus Torvalds  * megaraid_alloc_scb - detach and return a scb from the free list
12671da177e4SLinus Torvalds  * @adapter	: controller's soft state
1268a69b74d3SRandy Dunlap  * @scp		: pointer to the scsi command to be executed
12691da177e4SLinus Torvalds  *
1270a69b74d3SRandy Dunlap  * Return the scb from the head of the free list. %NULL if there are none
1271a69b74d3SRandy Dunlap  * available.
1272a69b74d3SRandy Dunlap  */
1273858119e1SArjan van de Ven static scb_t *
megaraid_alloc_scb(adapter_t * adapter,struct scsi_cmnd * scp)12741da177e4SLinus Torvalds megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
12751da177e4SLinus Torvalds {
12761da177e4SLinus Torvalds 	struct list_head	*head = &adapter->kscb_pool;
12771da177e4SLinus Torvalds 	scb_t			*scb = NULL;
12781da177e4SLinus Torvalds 	unsigned long		flags;
12791da177e4SLinus Torvalds 
12801da177e4SLinus Torvalds 	// detach scb from free pool
12811da177e4SLinus Torvalds 	spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds 	if (list_empty(head)) {
12841da177e4SLinus Torvalds 		spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
12851da177e4SLinus Torvalds 		return NULL;
12861da177e4SLinus Torvalds 	}
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	scb = list_entry(head->next, scb_t, list);
12891da177e4SLinus Torvalds 	list_del_init(&scb->list);
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds 	spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds 	scb->state	= SCB_ACTIVE;
12941da177e4SLinus Torvalds 	scb->scp	= scp;
12951da177e4SLinus Torvalds 	scb->dma_type	= MRAID_DMA_NONE;
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds 	return scb;
12981da177e4SLinus Torvalds }
12991da177e4SLinus Torvalds 
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds /**
13021da177e4SLinus Torvalds  * megaraid_dealloc_scb - return the scb to the free pool
13031da177e4SLinus Torvalds  * @adapter	: controller's soft state
13041da177e4SLinus Torvalds  * @scb		: scb to be freed
13051da177e4SLinus Torvalds  *
1306a69b74d3SRandy Dunlap  * Return the scb back to the free list of scbs. The caller must 'flush' the
13071da177e4SLinus Torvalds  * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc.
13081da177e4SLinus Torvalds  * NOTE NOTE: Make sure the scb is not on any list before calling this
13091da177e4SLinus Torvalds  * routine.
1310a69b74d3SRandy Dunlap  */
13111da177e4SLinus Torvalds static inline void
megaraid_dealloc_scb(adapter_t * adapter,scb_t * scb)13121da177e4SLinus Torvalds megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
13131da177e4SLinus Torvalds {
13141da177e4SLinus Torvalds 	unsigned long		flags;
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 	// put scb in the free pool
13171da177e4SLinus Torvalds 	scb->state	= SCB_FREE;
13181da177e4SLinus Torvalds 	scb->scp	= NULL;
13191da177e4SLinus Torvalds 	spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 	list_add(&scb->list, &adapter->kscb_pool);
13221da177e4SLinus Torvalds 
13231da177e4SLinus Torvalds 	spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
13241da177e4SLinus Torvalds 
13251da177e4SLinus Torvalds 	return;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds /**
13301da177e4SLinus Torvalds  * megaraid_mbox_mksgl - make the scatter-gather list
1331a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
1332a69b74d3SRandy Dunlap  * @scb		: scsi control block
13331da177e4SLinus Torvalds  *
1334a69b74d3SRandy Dunlap  * Prepare the scatter-gather list.
13351da177e4SLinus Torvalds  */
1336858119e1SArjan van de Ven static int
megaraid_mbox_mksgl(adapter_t * adapter,scb_t * scb)13371da177e4SLinus Torvalds megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
13381da177e4SLinus Torvalds {
13391da177e4SLinus Torvalds 	struct scatterlist	*sgl;
13401da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
13411da177e4SLinus Torvalds 	struct scsi_cmnd	*scp;
13421da177e4SLinus Torvalds 	int			sgcnt;
13431da177e4SLinus Torvalds 	int			i;
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	scp	= scb->scp;
13471da177e4SLinus Torvalds 	ccb	= (mbox_ccb_t *)scb->ccb;
13481da177e4SLinus Torvalds 
134932fbac22SFUJITA Tomonori 	sgcnt = scsi_dma_map(scp);
135032fbac22SFUJITA Tomonori 	BUG_ON(sgcnt < 0 || sgcnt > adapter->sglen);
135132fbac22SFUJITA Tomonori 
13521da177e4SLinus Torvalds 	// no mapping required if no data to be transferred
135332fbac22SFUJITA Tomonori 	if (!sgcnt)
13541da177e4SLinus Torvalds 		return 0;
13551da177e4SLinus Torvalds 
13561da177e4SLinus Torvalds 	scb->dma_type = MRAID_DMA_WSG;
13571da177e4SLinus Torvalds 
135832fbac22SFUJITA Tomonori 	scsi_for_each_sg(scp, sgl, sgcnt, i) {
13591da177e4SLinus Torvalds 		ccb->sgl64[i].address	= sg_dma_address(sgl);
13601da177e4SLinus Torvalds 		ccb->sgl64[i].length	= sg_dma_len(sgl);
13611da177e4SLinus Torvalds 	}
13621da177e4SLinus Torvalds 
13631da177e4SLinus Torvalds 	// Return count of SG nodes
13641da177e4SLinus Torvalds 	return sgcnt;
13651da177e4SLinus Torvalds }
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 
13681da177e4SLinus Torvalds /**
13691da177e4SLinus Torvalds  * mbox_post_cmd - issue a mailbox command
1370a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
1371a69b74d3SRandy Dunlap  * @scb		: command to be issued
13721da177e4SLinus Torvalds  *
1373a69b74d3SRandy Dunlap  * Post the command to the controller if mailbox is available.
13741da177e4SLinus Torvalds  */
1375858119e1SArjan van de Ven static int
mbox_post_cmd(adapter_t * adapter,scb_t * scb)13761da177e4SLinus Torvalds mbox_post_cmd(adapter_t *adapter, scb_t *scb)
13771da177e4SLinus Torvalds {
13781da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
13791da177e4SLinus Torvalds 	mbox64_t	*mbox64;
13801da177e4SLinus Torvalds 	mbox_t		*mbox;
13811da177e4SLinus Torvalds 	mbox_ccb_t	*ccb;
13821da177e4SLinus Torvalds 	unsigned long	flags;
13831da177e4SLinus Torvalds 	unsigned int	i = 0;
13841da177e4SLinus Torvalds 
13851da177e4SLinus Torvalds 
13861da177e4SLinus Torvalds 	ccb	= (mbox_ccb_t *)scb->ccb;
13871da177e4SLinus Torvalds 	mbox	= raid_dev->mbox;
13881da177e4SLinus Torvalds 	mbox64	= raid_dev->mbox64;
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 	/*
13911da177e4SLinus Torvalds 	 * Check for busy mailbox. If it is, return failure - the caller
13921da177e4SLinus Torvalds 	 * should retry later.
13931da177e4SLinus Torvalds 	 */
13941da177e4SLinus Torvalds 	spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 	if (unlikely(mbox->busy)) {
13971da177e4SLinus Torvalds 		do {
13981da177e4SLinus Torvalds 			udelay(1);
13991da177e4SLinus Torvalds 			i++;
14001da177e4SLinus Torvalds 			rmb();
14011da177e4SLinus Torvalds 		} while(mbox->busy && (i < max_mbox_busy_wait));
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 		if (mbox->busy) {
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 			spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
14061da177e4SLinus Torvalds 
14071da177e4SLinus Torvalds 			return -1;
14081da177e4SLinus Torvalds 		}
14091da177e4SLinus Torvalds 	}
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 	// Copy this command's mailbox data into "adapter's" mailbox
14131da177e4SLinus Torvalds 	memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22);
14141da177e4SLinus Torvalds 	mbox->cmdid = scb->sno;
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds 	adapter->outstanding_cmds++;
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds 	mbox->busy	= 1;	// Set busy
14191da177e4SLinus Torvalds 	mbox->poll	= 0;
14201da177e4SLinus Torvalds 	mbox->ack	= 0;
14211da177e4SLinus Torvalds 	wmb();
14221da177e4SLinus Torvalds 
14231da177e4SLinus Torvalds 	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
14241da177e4SLinus Torvalds 
14251da177e4SLinus Torvalds 	spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds 	return 0;
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 
14311da177e4SLinus Torvalds /**
1432d4f5ae21SLee Jones  * megaraid_queue_command_lck - generic queue entry point for all LLDs
14331da177e4SLinus Torvalds  * @scp		: pointer to the scsi command to be executed
14341da177e4SLinus Torvalds  *
14351da177e4SLinus Torvalds  * Queue entry point for mailbox based controllers.
14361da177e4SLinus Torvalds  */
megaraid_queue_command_lck(struct scsi_cmnd * scp)1437af049dfdSBart Van Assche static int megaraid_queue_command_lck(struct scsi_cmnd *scp)
14381da177e4SLinus Torvalds {
1439af049dfdSBart Van Assche 	void (*done)(struct scsi_cmnd *) = scsi_done;
14401da177e4SLinus Torvalds 	adapter_t	*adapter;
14411da177e4SLinus Torvalds 	scb_t		*scb;
14421da177e4SLinus Torvalds 	int		if_busy;
14431da177e4SLinus Torvalds 
14441da177e4SLinus Torvalds 	adapter		= SCP2ADAPTER(scp);
14451da177e4SLinus Torvalds 	scp->result	= 0;
14461da177e4SLinus Torvalds 
14471da177e4SLinus Torvalds 	/*
14481da177e4SLinus Torvalds 	 * Allocate and build a SCB request
14491da177e4SLinus Torvalds 	 * if_busy flag will be set if megaraid_mbox_build_cmd() command could
14501da177e4SLinus Torvalds 	 * not allocate scb. We will return non-zero status in that case.
14511da177e4SLinus Torvalds 	 * NOTE: scb can be null even though certain commands completed
14521da177e4SLinus Torvalds 	 * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would
14531da177e4SLinus Torvalds 	 * return 0 in that case, and we would do the callback right away.
14541da177e4SLinus Torvalds 	 */
14551da177e4SLinus Torvalds 	if_busy	= 0;
14561da177e4SLinus Torvalds 	scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy);
14571da177e4SLinus Torvalds 	if (!scb) {	// command already completed
14581da177e4SLinus Torvalds 		done(scp);
14591da177e4SLinus Torvalds 		return 0;
14601da177e4SLinus Torvalds 	}
14611da177e4SLinus Torvalds 
1462f2c8dc40SChristoph Hellwig 	megaraid_mbox_runpendq(adapter, scb);
14631da177e4SLinus Torvalds 	return if_busy;
14641da177e4SLinus Torvalds }
14651da177e4SLinus Torvalds 
DEF_SCSI_QCMD(megaraid_queue_command)1466f281233dSJeff Garzik static DEF_SCSI_QCMD(megaraid_queue_command)
1467f281233dSJeff Garzik 
14681da177e4SLinus Torvalds /**
1469a69b74d3SRandy Dunlap  * megaraid_mbox_build_cmd - transform the mid-layer scsi commands
1470a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
1471a69b74d3SRandy Dunlap  * @scp		: mid-layer scsi command pointer
1472a69b74d3SRandy Dunlap  * @busy	: set if request could not be completed because of lack of
14731da177e4SLinus Torvalds  *		resources
14741da177e4SLinus Torvalds  *
1475a69b74d3SRandy Dunlap  * Transform the mid-layer scsi command to megaraid firmware lingua.
1476a69b74d3SRandy Dunlap  * Convert the command issued by mid-layer to format understood by megaraid
1477a69b74d3SRandy Dunlap  * firmware. We also complete certain commands without sending them to firmware.
14781da177e4SLinus Torvalds  */
14791da177e4SLinus Torvalds static scb_t *
14801da177e4SLinus Torvalds megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
14811da177e4SLinus Torvalds {
14821da177e4SLinus Torvalds 	mraid_device_t		*rdev = ADAP2RAIDDEV(adapter);
14831da177e4SLinus Torvalds 	int			channel;
14841da177e4SLinus Torvalds 	int			target;
14851da177e4SLinus Torvalds 	int			islogical;
14861da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
14871da177e4SLinus Torvalds 	mraid_passthru_t	*pthru;
14881da177e4SLinus Torvalds 	mbox64_t		*mbox64;
14891da177e4SLinus Torvalds 	mbox_t			*mbox;
14901da177e4SLinus Torvalds 	scb_t			*scb;
14911da177e4SLinus Torvalds 	char			skip[] = "skipping";
14921da177e4SLinus Torvalds 	char			scan[] = "scanning";
14931da177e4SLinus Torvalds 	char			*ss;
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds 
14961da177e4SLinus Torvalds 	/*
14971da177e4SLinus Torvalds 	 * Get the appropriate device map for the device this command is
14981da177e4SLinus Torvalds 	 * intended for
14991da177e4SLinus Torvalds 	 */
15001da177e4SLinus Torvalds 	MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical);
15011da177e4SLinus Torvalds 
15021da177e4SLinus Torvalds 	/*
15031da177e4SLinus Torvalds 	 * Logical drive commands
15041da177e4SLinus Torvalds 	 */
15051da177e4SLinus Torvalds 	if (islogical) {
15061da177e4SLinus Torvalds 		switch (scp->cmnd[0]) {
15071da177e4SLinus Torvalds 		case TEST_UNIT_READY:
15081da177e4SLinus Torvalds 			/*
15091da177e4SLinus Torvalds 			 * Do we support clustering and is the support enabled
15101da177e4SLinus Torvalds 			 * If no, return success always
15111da177e4SLinus Torvalds 			 */
15121da177e4SLinus Torvalds 			if (!adapter->ha) {
15131da177e4SLinus Torvalds 				scp->result = (DID_OK << 16);
15141da177e4SLinus Torvalds 				return NULL;
15151da177e4SLinus Torvalds 			}
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds 			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
15181da177e4SLinus Torvalds 				scp->result = (DID_ERROR << 16);
15191da177e4SLinus Torvalds 				*busy = 1;
15201da177e4SLinus Torvalds 				return NULL;
15211da177e4SLinus Torvalds 			}
15221da177e4SLinus Torvalds 
15231da177e4SLinus Torvalds 			scb->dma_direction	= scp->sc_data_direction;
15241da177e4SLinus Torvalds 			scb->dev_channel	= 0xFF;
15251da177e4SLinus Torvalds 			scb->dev_target		= target;
15261da177e4SLinus Torvalds 			ccb			= (mbox_ccb_t *)scb->ccb;
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 			/*
15291da177e4SLinus Torvalds 			 * The command id will be provided by the command
15301da177e4SLinus Torvalds 			 * issuance routine
15311da177e4SLinus Torvalds 			 */
15321da177e4SLinus Torvalds 			ccb->raw_mbox[0]	= CLUSTER_CMD;
15331da177e4SLinus Torvalds 			ccb->raw_mbox[2]	= RESERVATION_STATUS;
15341da177e4SLinus Torvalds 			ccb->raw_mbox[3]	= target;
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 			return scb;
15371da177e4SLinus Torvalds 
15381da177e4SLinus Torvalds 		case MODE_SENSE:
153932fbac22SFUJITA Tomonori 		{
15401da177e4SLinus Torvalds 			struct scatterlist	*sgl;
15411da177e4SLinus Torvalds 			caddr_t			vaddr;
15421da177e4SLinus Torvalds 
154332fbac22SFUJITA Tomonori 			sgl = scsi_sglist(scp);
154445711f1aSJens Axboe 			if (sg_page(sgl)) {
154545711f1aSJens Axboe 				vaddr = (caddr_t) sg_virt(&sgl[0]);
15461da177e4SLinus Torvalds 
15471da177e4SLinus Torvalds 				memset(vaddr, 0, scp->cmnd[4]);
15481da177e4SLinus Torvalds 			}
15491da177e4SLinus Torvalds 			else {
15501da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_WARNING
15511da177e4SLinus Torvalds 						 "megaraid mailbox: invalid sg:%d\n",
15521da177e4SLinus Torvalds 						 __LINE__));
15531da177e4SLinus Torvalds 			}
15541da177e4SLinus Torvalds 		}
15551da177e4SLinus Torvalds 		scp->result = (DID_OK << 16);
15561da177e4SLinus Torvalds 		return NULL;
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds 		case INQUIRY:
15591da177e4SLinus Torvalds 			/*
15601da177e4SLinus Torvalds 			 * Display the channel scan for logical drives
15611da177e4SLinus Torvalds 			 * Do not display scan for a channel if already done.
15621da177e4SLinus Torvalds 			 */
15631da177e4SLinus Torvalds 			if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
15641da177e4SLinus Torvalds 
15651da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_INFO
15661da177e4SLinus Torvalds 					"scsi[%d]: scanning scsi channel %d",
15671da177e4SLinus Torvalds 					adapter->host->host_no,
15681da177e4SLinus Torvalds 					SCP2CHANNEL(scp)));
15691da177e4SLinus Torvalds 
15701da177e4SLinus Torvalds 				con_log(CL_ANN, (
15711da177e4SLinus Torvalds 					" [virtual] for logical drives\n"));
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 				rdev->last_disp |= (1L << SCP2CHANNEL(scp));
15741da177e4SLinus Torvalds 			}
15751da177e4SLinus Torvalds 
1576aa677bc7SJu, Seokmann 			if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) {
1577f2b1e9c6SHannes Reinecke 				scsi_build_sense(scp, 0, ILLEGAL_REQUEST,
1578f2b1e9c6SHannes Reinecke 						 MEGA_INVALID_FIELD_IN_CDB, 0);
1579aa677bc7SJu, Seokmann 				return NULL;
1580aa677bc7SJu, Seokmann 			}
1581aa677bc7SJu, Seokmann 
1582df561f66SGustavo A. R. Silva 			fallthrough;
15831da177e4SLinus Torvalds 
15841da177e4SLinus Torvalds 		case READ_CAPACITY:
15851da177e4SLinus Torvalds 			/*
15861da177e4SLinus Torvalds 			 * Do not allow LUN > 0 for logical drives and
15871da177e4SLinus Torvalds 			 * requests for more than 40 logical drives
15881da177e4SLinus Torvalds 			 */
15891da177e4SLinus Torvalds 			if (SCP2LUN(scp)) {
15901da177e4SLinus Torvalds 				scp->result = (DID_BAD_TARGET << 16);
15911da177e4SLinus Torvalds 				return NULL;
15921da177e4SLinus Torvalds 			}
15931da177e4SLinus Torvalds 			if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) {
15941da177e4SLinus Torvalds 				scp->result = (DID_BAD_TARGET << 16);
15951da177e4SLinus Torvalds 				return NULL;
15961da177e4SLinus Torvalds 			}
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds 
15991da177e4SLinus Torvalds 			/* Allocate a SCB and initialize passthru */
16001da177e4SLinus Torvalds 			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
16011da177e4SLinus Torvalds 				scp->result = (DID_ERROR << 16);
16021da177e4SLinus Torvalds 				*busy = 1;
16031da177e4SLinus Torvalds 				return NULL;
16041da177e4SLinus Torvalds 			}
16051da177e4SLinus Torvalds 
16061da177e4SLinus Torvalds 			ccb			= (mbox_ccb_t *)scb->ccb;
16071da177e4SLinus Torvalds 			scb->dev_channel	= 0xFF;
16081da177e4SLinus Torvalds 			scb->dev_target		= target;
16091da177e4SLinus Torvalds 			pthru			= ccb->pthru;
16101da177e4SLinus Torvalds 			mbox			= ccb->mbox;
16111da177e4SLinus Torvalds 			mbox64			= ccb->mbox64;
16121da177e4SLinus Torvalds 
16131da177e4SLinus Torvalds 			pthru->timeout		= 0;
16141da177e4SLinus Torvalds 			pthru->ars		= 1;
16151da177e4SLinus Torvalds 			pthru->reqsenselen	= 14;
16161da177e4SLinus Torvalds 			pthru->islogical	= 1;
16171da177e4SLinus Torvalds 			pthru->logdrv		= target;
16181da177e4SLinus Torvalds 			pthru->cdblen		= scp->cmd_len;
16191da177e4SLinus Torvalds 			memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
16201da177e4SLinus Torvalds 
16211da177e4SLinus Torvalds 			mbox->cmd		= MBOXCMD_PASSTHRU64;
16221da177e4SLinus Torvalds 			scb->dma_direction	= scp->sc_data_direction;
16231da177e4SLinus Torvalds 
162432fbac22SFUJITA Tomonori 			pthru->dataxferlen	= scsi_bufflen(scp);
16251da177e4SLinus Torvalds 			pthru->dataxferaddr	= ccb->sgl_dma_h;
16261da177e4SLinus Torvalds 			pthru->numsge		= megaraid_mbox_mksgl(adapter,
16271da177e4SLinus Torvalds 							scb);
16281da177e4SLinus Torvalds 
16291da177e4SLinus Torvalds 			mbox->xferaddr		= 0xFFFFFFFF;
16301da177e4SLinus Torvalds 			mbox64->xferaddr_lo	= (uint32_t )ccb->pthru_dma_h;
16311da177e4SLinus Torvalds 			mbox64->xferaddr_hi	= 0;
16321da177e4SLinus Torvalds 
16331da177e4SLinus Torvalds 			return scb;
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 		case READ_6:
16361da177e4SLinus Torvalds 		case WRITE_6:
16371da177e4SLinus Torvalds 		case READ_10:
16381da177e4SLinus Torvalds 		case WRITE_10:
16391da177e4SLinus Torvalds 		case READ_12:
16401da177e4SLinus Torvalds 		case WRITE_12:
16411da177e4SLinus Torvalds 
16421da177e4SLinus Torvalds 			/*
16431da177e4SLinus Torvalds 			 * Allocate a SCB and initialize mailbox
16441da177e4SLinus Torvalds 			 */
16451da177e4SLinus Torvalds 			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
16461da177e4SLinus Torvalds 				scp->result = (DID_ERROR << 16);
16471da177e4SLinus Torvalds 				*busy = 1;
16481da177e4SLinus Torvalds 				return NULL;
16491da177e4SLinus Torvalds 			}
16501da177e4SLinus Torvalds 			ccb			= (mbox_ccb_t *)scb->ccb;
16511da177e4SLinus Torvalds 			scb->dev_channel	= 0xFF;
16521da177e4SLinus Torvalds 			scb->dev_target		= target;
16531da177e4SLinus Torvalds 			mbox			= ccb->mbox;
16541da177e4SLinus Torvalds 			mbox64			= ccb->mbox64;
16551da177e4SLinus Torvalds 			mbox->logdrv		= target;
16561da177e4SLinus Torvalds 
16571da177e4SLinus Torvalds 			/*
16581da177e4SLinus Torvalds 			 * A little HACK: 2nd bit is zero for all scsi read
16591da177e4SLinus Torvalds 			 * commands and is set for all scsi write commands
16601da177e4SLinus Torvalds 			 */
16611da177e4SLinus Torvalds 			mbox->cmd = (scp->cmnd[0] & 0x02) ?  MBOXCMD_LWRITE64:
16621da177e4SLinus Torvalds 					MBOXCMD_LREAD64 ;
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds 			/*
16651da177e4SLinus Torvalds 			 * 6-byte READ(0x08) or WRITE(0x0A) cdb
16661da177e4SLinus Torvalds 			 */
16671da177e4SLinus Torvalds 			if (scp->cmd_len == 6) {
16681da177e4SLinus Torvalds 				mbox->numsectors = (uint32_t)scp->cmnd[4];
16691da177e4SLinus Torvalds 				mbox->lba =
16701da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[1] << 16)	|
16711da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[2] << 8)	|
16721da177e4SLinus Torvalds 					(uint32_t)scp->cmnd[3];
16731da177e4SLinus Torvalds 
16741da177e4SLinus Torvalds 				mbox->lba &= 0x1FFFFF;
16751da177e4SLinus Torvalds 			}
16761da177e4SLinus Torvalds 
16771da177e4SLinus Torvalds 			/*
16781da177e4SLinus Torvalds 			 * 10-byte READ(0x28) or WRITE(0x2A) cdb
16791da177e4SLinus Torvalds 			 */
16801da177e4SLinus Torvalds 			else if (scp->cmd_len == 10) {
16811da177e4SLinus Torvalds 				mbox->numsectors =
16821da177e4SLinus Torvalds 					(uint32_t)scp->cmnd[8] |
16831da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[7] << 8);
16841da177e4SLinus Torvalds 				mbox->lba =
16851da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[2] << 24) |
16861da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[3] << 16) |
16871da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[4] << 8) |
16881da177e4SLinus Torvalds 					(uint32_t)scp->cmnd[5];
16891da177e4SLinus Torvalds 			}
16901da177e4SLinus Torvalds 
16911da177e4SLinus Torvalds 			/*
16921da177e4SLinus Torvalds 			 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
16931da177e4SLinus Torvalds 			 */
16941da177e4SLinus Torvalds 			else if (scp->cmd_len == 12) {
16951da177e4SLinus Torvalds 				mbox->lba =
16961da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[2] << 24) |
16971da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[3] << 16) |
16981da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[4] << 8) |
16991da177e4SLinus Torvalds 					(uint32_t)scp->cmnd[5];
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 				mbox->numsectors =
17021da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[6] << 24) |
17031da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[7] << 16) |
17041da177e4SLinus Torvalds 					((uint32_t)scp->cmnd[8] << 8) |
17051da177e4SLinus Torvalds 					(uint32_t)scp->cmnd[9];
17061da177e4SLinus Torvalds 			}
17071da177e4SLinus Torvalds 			else {
17081da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_WARNING
17091da177e4SLinus Torvalds 					"megaraid: unsupported CDB length\n"));
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 				megaraid_dealloc_scb(adapter, scb);
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 				scp->result = (DID_ERROR << 16);
17141da177e4SLinus Torvalds 				return NULL;
17151da177e4SLinus Torvalds 			}
17161da177e4SLinus Torvalds 
17171da177e4SLinus Torvalds 			scb->dma_direction = scp->sc_data_direction;
17181da177e4SLinus Torvalds 
17191da177e4SLinus Torvalds 			// Calculate Scatter-Gather info
17201da177e4SLinus Torvalds 			mbox64->xferaddr_lo	= (uint32_t )ccb->sgl_dma_h;
17211da177e4SLinus Torvalds 			mbox->numsge		= megaraid_mbox_mksgl(adapter,
17221da177e4SLinus Torvalds 							scb);
17231da177e4SLinus Torvalds 			mbox->xferaddr		= 0xFFFFFFFF;
17241da177e4SLinus Torvalds 			mbox64->xferaddr_hi	= 0;
17251da177e4SLinus Torvalds 
17261da177e4SLinus Torvalds 			return scb;
17271da177e4SLinus Torvalds 
17281da177e4SLinus Torvalds 		case RESERVE:
17291da177e4SLinus Torvalds 		case RELEASE:
17301da177e4SLinus Torvalds 			/*
17311da177e4SLinus Torvalds 			 * Do we support clustering and is the support enabled
17321da177e4SLinus Torvalds 			 */
17331da177e4SLinus Torvalds 			if (!adapter->ha) {
17341da177e4SLinus Torvalds 				scp->result = (DID_BAD_TARGET << 16);
17351da177e4SLinus Torvalds 				return NULL;
17361da177e4SLinus Torvalds 			}
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 			/*
17391da177e4SLinus Torvalds 			 * Allocate a SCB and initialize mailbox
17401da177e4SLinus Torvalds 			 */
17411da177e4SLinus Torvalds 			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
17421da177e4SLinus Torvalds 				scp->result = (DID_ERROR << 16);
17431da177e4SLinus Torvalds 				*busy = 1;
17441da177e4SLinus Torvalds 				return NULL;
17451da177e4SLinus Torvalds 			}
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds 			ccb			= (mbox_ccb_t *)scb->ccb;
17481da177e4SLinus Torvalds 			scb->dev_channel	= 0xFF;
17491da177e4SLinus Torvalds 			scb->dev_target		= target;
17501da177e4SLinus Torvalds 			ccb->raw_mbox[0]	= CLUSTER_CMD;
17511da177e4SLinus Torvalds 			ccb->raw_mbox[2]	=  (scp->cmnd[0] == RESERVE) ?
17521da177e4SLinus Torvalds 						RESERVE_LD : RELEASE_LD;
17531da177e4SLinus Torvalds 
17541da177e4SLinus Torvalds 			ccb->raw_mbox[3]	= target;
17551da177e4SLinus Torvalds 			scb->dma_direction	= scp->sc_data_direction;
17561da177e4SLinus Torvalds 
17571da177e4SLinus Torvalds 			return scb;
17581da177e4SLinus Torvalds 
17591da177e4SLinus Torvalds 		default:
17601da177e4SLinus Torvalds 			scp->result = (DID_BAD_TARGET << 16);
17611da177e4SLinus Torvalds 			return NULL;
17621da177e4SLinus Torvalds 		}
17631da177e4SLinus Torvalds 	}
17641da177e4SLinus Torvalds 	else { // Passthru device commands
17651da177e4SLinus Torvalds 
17661da177e4SLinus Torvalds 		// Do not allow access to target id > 15 or LUN > 7
17671da177e4SLinus Torvalds 		if (target > 15 || SCP2LUN(scp) > 7) {
17681da177e4SLinus Torvalds 			scp->result = (DID_BAD_TARGET << 16);
17691da177e4SLinus Torvalds 			return NULL;
17701da177e4SLinus Torvalds 		}
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds 		// if fast load option was set and scan for last device is
17731da177e4SLinus Torvalds 		// over, reset the fast_load flag so that during a possible
17741da177e4SLinus Torvalds 		// next scan, devices can be made available
17751da177e4SLinus Torvalds 		if (rdev->fast_load && (target == 15) &&
17761da177e4SLinus Torvalds 			(SCP2CHANNEL(scp) == adapter->max_channel -1)) {
17771da177e4SLinus Torvalds 
17781da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_INFO
17791da177e4SLinus Torvalds 			"megaraid[%d]: physical device scan re-enabled\n",
17801da177e4SLinus Torvalds 				adapter->host->host_no));
17811da177e4SLinus Torvalds 			rdev->fast_load = 0;
17821da177e4SLinus Torvalds 		}
17831da177e4SLinus Torvalds 
17841da177e4SLinus Torvalds 		/*
17851da177e4SLinus Torvalds 		 * Display the channel scan for physical devices
17861da177e4SLinus Torvalds 		 */
17871da177e4SLinus Torvalds 		if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
17881da177e4SLinus Torvalds 
17891da177e4SLinus Torvalds 			ss = rdev->fast_load ? skip : scan;
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_INFO
17921da177e4SLinus Torvalds 				"scsi[%d]: %s scsi channel %d [Phy %d]",
17931da177e4SLinus Torvalds 				adapter->host->host_no, ss, SCP2CHANNEL(scp),
17941da177e4SLinus Torvalds 				channel));
17951da177e4SLinus Torvalds 
17961da177e4SLinus Torvalds 			con_log(CL_ANN, (
17971da177e4SLinus Torvalds 				" for non-raid devices\n"));
17981da177e4SLinus Torvalds 
17991da177e4SLinus Torvalds 			rdev->last_disp |= (1L << SCP2CHANNEL(scp));
18001da177e4SLinus Torvalds 		}
18011da177e4SLinus Torvalds 
18021da177e4SLinus Torvalds 		// disable channel sweep if fast load option given
18031da177e4SLinus Torvalds 		if (rdev->fast_load) {
18041da177e4SLinus Torvalds 			scp->result = (DID_BAD_TARGET << 16);
18051da177e4SLinus Torvalds 			return NULL;
18061da177e4SLinus Torvalds 		}
18071da177e4SLinus Torvalds 
18081da177e4SLinus Torvalds 		// Allocate a SCB and initialize passthru
18091da177e4SLinus Torvalds 		if (!(scb = megaraid_alloc_scb(adapter, scp))) {
18101da177e4SLinus Torvalds 			scp->result = (DID_ERROR << 16);
18111da177e4SLinus Torvalds 			*busy = 1;
18121da177e4SLinus Torvalds 			return NULL;
18131da177e4SLinus Torvalds 		}
18141da177e4SLinus Torvalds 
18151da177e4SLinus Torvalds 		ccb			= (mbox_ccb_t *)scb->ccb;
18161da177e4SLinus Torvalds 		scb->dev_channel	= channel;
18171da177e4SLinus Torvalds 		scb->dev_target		= target;
18181da177e4SLinus Torvalds 		scb->dma_direction	= scp->sc_data_direction;
18191da177e4SLinus Torvalds 		mbox			= ccb->mbox;
18201da177e4SLinus Torvalds 		mbox64			= ccb->mbox64;
18211da177e4SLinus Torvalds 
18221da177e4SLinus Torvalds 		// Does this firmware support extended CDBs
18231da177e4SLinus Torvalds 		if (adapter->max_cdb_sz == 16) {
18241da177e4SLinus Torvalds 			mbox->cmd		= MBOXCMD_EXTPTHRU;
18251da177e4SLinus Torvalds 
18261da177e4SLinus Torvalds 			megaraid_mbox_prepare_epthru(adapter, scb, scp);
18271da177e4SLinus Torvalds 
18281da177e4SLinus Torvalds 			mbox64->xferaddr_lo	= (uint32_t)ccb->epthru_dma_h;
18291da177e4SLinus Torvalds 			mbox64->xferaddr_hi	= 0;
18301da177e4SLinus Torvalds 			mbox->xferaddr		= 0xFFFFFFFF;
18311da177e4SLinus Torvalds 		}
18321da177e4SLinus Torvalds 		else {
18331da177e4SLinus Torvalds 			mbox->cmd = MBOXCMD_PASSTHRU64;
18341da177e4SLinus Torvalds 
18351da177e4SLinus Torvalds 			megaraid_mbox_prepare_pthru(adapter, scb, scp);
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 			mbox64->xferaddr_lo	= (uint32_t)ccb->pthru_dma_h;
18381da177e4SLinus Torvalds 			mbox64->xferaddr_hi	= 0;
18391da177e4SLinus Torvalds 			mbox->xferaddr		= 0xFFFFFFFF;
18401da177e4SLinus Torvalds 		}
18411da177e4SLinus Torvalds 		return scb;
18421da177e4SLinus Torvalds 	}
18431da177e4SLinus Torvalds 
18441da177e4SLinus Torvalds 	// NOT REACHED
18451da177e4SLinus Torvalds }
18461da177e4SLinus Torvalds 
18471da177e4SLinus Torvalds 
18481da177e4SLinus Torvalds /**
18491da177e4SLinus Torvalds  * megaraid_mbox_runpendq - execute commands queued in the pending queue
18501da177e4SLinus Torvalds  * @adapter	: controller's soft state
1851a69b74d3SRandy Dunlap  * @scb_q	: SCB to be queued in the pending list
18521da177e4SLinus Torvalds  *
1853a69b74d3SRandy Dunlap  * Scan the pending list for commands which are not yet issued and try to
18541da177e4SLinus Torvalds  * post to the controller. The SCB can be a null pointer, which would indicate
18551da177e4SLinus Torvalds  * no SCB to be queue, just try to execute the ones in the pending list.
18561da177e4SLinus Torvalds  *
18571da177e4SLinus Torvalds  * NOTE: We do not actually traverse the pending list. The SCBs are plucked
18581da177e4SLinus Torvalds  * out from the head of the pending list. If it is successfully issued, the
18591da177e4SLinus Torvalds  * next SCB is at the head now.
18601da177e4SLinus Torvalds  */
18611da177e4SLinus Torvalds static void
megaraid_mbox_runpendq(adapter_t * adapter,scb_t * scb_q)18621da177e4SLinus Torvalds megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q)
18631da177e4SLinus Torvalds {
18641da177e4SLinus Torvalds 	scb_t			*scb;
18651da177e4SLinus Torvalds 	unsigned long		flags;
18661da177e4SLinus Torvalds 
18671da177e4SLinus Torvalds 	spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
18681da177e4SLinus Torvalds 
18691da177e4SLinus Torvalds 	if (scb_q) {
18701da177e4SLinus Torvalds 		scb_q->state = SCB_PENDQ;
18711da177e4SLinus Torvalds 		list_add_tail(&scb_q->list, &adapter->pend_list);
18721da177e4SLinus Torvalds 	}
18731da177e4SLinus Torvalds 
18741da177e4SLinus Torvalds 	// if the adapter in not in quiescent mode, post the commands to FW
18751da177e4SLinus Torvalds 	if (adapter->quiescent) {
18761da177e4SLinus Torvalds 		spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
18771da177e4SLinus Torvalds 		return;
18781da177e4SLinus Torvalds 	}
18791da177e4SLinus Torvalds 
18801da177e4SLinus Torvalds 	while (!list_empty(&adapter->pend_list)) {
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 		assert_spin_locked(PENDING_LIST_LOCK(adapter));
18831da177e4SLinus Torvalds 
18841da177e4SLinus Torvalds 		scb = list_entry(adapter->pend_list.next, scb_t, list);
18851da177e4SLinus Torvalds 
18861da177e4SLinus Torvalds 		// remove the scb from the pending list and try to
18871da177e4SLinus Torvalds 		// issue. If we are unable to issue it, put back in
18881da177e4SLinus Torvalds 		// the pending list and return
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds 		list_del_init(&scb->list);
18911da177e4SLinus Torvalds 
18921da177e4SLinus Torvalds 		spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
18931da177e4SLinus Torvalds 
18941da177e4SLinus Torvalds 		// if mailbox was busy, return SCB back to pending
18951da177e4SLinus Torvalds 		// list. Make sure to add at the head, since that's
18961da177e4SLinus Torvalds 		// where it would have been removed from
18971da177e4SLinus Torvalds 
18981da177e4SLinus Torvalds 		scb->state = SCB_ISSUED;
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds 		if (mbox_post_cmd(adapter, scb) != 0) {
19011da177e4SLinus Torvalds 
19021da177e4SLinus Torvalds 			spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
19031da177e4SLinus Torvalds 
19041da177e4SLinus Torvalds 			scb->state = SCB_PENDQ;
19051da177e4SLinus Torvalds 
19061da177e4SLinus Torvalds 			list_add(&scb->list, &adapter->pend_list);
19071da177e4SLinus Torvalds 
19081da177e4SLinus Torvalds 			spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
19091da177e4SLinus Torvalds 				flags);
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds 			return;
19121da177e4SLinus Torvalds 		}
19131da177e4SLinus Torvalds 
19141da177e4SLinus Torvalds 		spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
19151da177e4SLinus Torvalds 	}
19161da177e4SLinus Torvalds 
19171da177e4SLinus Torvalds 	spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
19181da177e4SLinus Torvalds 
19191da177e4SLinus Torvalds 
19201da177e4SLinus Torvalds 	return;
19211da177e4SLinus Torvalds }
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds 
19241da177e4SLinus Torvalds /**
19251da177e4SLinus Torvalds  * megaraid_mbox_prepare_pthru - prepare a command for physical devices
1926a69b74d3SRandy Dunlap  * @adapter	: pointer to controller's soft state
1927a69b74d3SRandy Dunlap  * @scb		: scsi control block
1928a69b74d3SRandy Dunlap  * @scp		: scsi command from the mid-layer
19291da177e4SLinus Torvalds  *
1930a69b74d3SRandy Dunlap  * Prepare a command for the scsi physical devices.
19311da177e4SLinus Torvalds  */
19321da177e4SLinus Torvalds static void
megaraid_mbox_prepare_pthru(adapter_t * adapter,scb_t * scb,struct scsi_cmnd * scp)19331da177e4SLinus Torvalds megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
19341da177e4SLinus Torvalds 		struct scsi_cmnd *scp)
19351da177e4SLinus Torvalds {
19361da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
19371da177e4SLinus Torvalds 	mraid_passthru_t	*pthru;
19381da177e4SLinus Torvalds 	uint8_t			channel;
19391da177e4SLinus Torvalds 	uint8_t			target;
19401da177e4SLinus Torvalds 
19411da177e4SLinus Torvalds 	ccb	= (mbox_ccb_t *)scb->ccb;
19421da177e4SLinus Torvalds 	pthru	= ccb->pthru;
19431da177e4SLinus Torvalds 	channel	= scb->dev_channel;
19441da177e4SLinus Torvalds 	target	= scb->dev_target;
19451da177e4SLinus Torvalds 
19461da177e4SLinus Torvalds 	// 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout
19471da177e4SLinus Torvalds 	pthru->timeout		= 4;
19481da177e4SLinus Torvalds 	pthru->ars		= 1;
19491da177e4SLinus Torvalds 	pthru->islogical	= 0;
19501da177e4SLinus Torvalds 	pthru->channel		= 0;
19511da177e4SLinus Torvalds 	pthru->target		= (channel << 4) | target;
19521da177e4SLinus Torvalds 	pthru->logdrv		= SCP2LUN(scp);
19531da177e4SLinus Torvalds 	pthru->reqsenselen	= 14;
19541da177e4SLinus Torvalds 	pthru->cdblen		= scp->cmd_len;
19551da177e4SLinus Torvalds 
19561da177e4SLinus Torvalds 	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
19571da177e4SLinus Torvalds 
195832fbac22SFUJITA Tomonori 	if (scsi_bufflen(scp)) {
195932fbac22SFUJITA Tomonori 		pthru->dataxferlen	= scsi_bufflen(scp);
19601da177e4SLinus Torvalds 		pthru->dataxferaddr	= ccb->sgl_dma_h;
19611da177e4SLinus Torvalds 		pthru->numsge		= megaraid_mbox_mksgl(adapter, scb);
19621da177e4SLinus Torvalds 	}
19631da177e4SLinus Torvalds 	else {
19641da177e4SLinus Torvalds 		pthru->dataxferaddr	= 0;
19651da177e4SLinus Torvalds 		pthru->dataxferlen	= 0;
19661da177e4SLinus Torvalds 		pthru->numsge		= 0;
19671da177e4SLinus Torvalds 	}
19681da177e4SLinus Torvalds 	return;
19691da177e4SLinus Torvalds }
19701da177e4SLinus Torvalds 
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds /**
19731da177e4SLinus Torvalds  * megaraid_mbox_prepare_epthru - prepare a command for physical devices
1974a69b74d3SRandy Dunlap  * @adapter	: pointer to controller's soft state
1975a69b74d3SRandy Dunlap  * @scb		: scsi control block
1976a69b74d3SRandy Dunlap  * @scp		: scsi command from the mid-layer
19771da177e4SLinus Torvalds  *
19783948ff8bSMatthias Schid  * Prepare a command for the scsi physical devices. This routine prepares
1979a69b74d3SRandy Dunlap  * commands for devices which can take extended CDBs (>10 bytes).
19801da177e4SLinus Torvalds  */
19811da177e4SLinus Torvalds static void
megaraid_mbox_prepare_epthru(adapter_t * adapter,scb_t * scb,struct scsi_cmnd * scp)19821da177e4SLinus Torvalds megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
19831da177e4SLinus Torvalds 		struct scsi_cmnd *scp)
19841da177e4SLinus Torvalds {
19851da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
19861da177e4SLinus Torvalds 	mraid_epassthru_t	*epthru;
19871da177e4SLinus Torvalds 	uint8_t			channel;
19881da177e4SLinus Torvalds 	uint8_t			target;
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds 	ccb	= (mbox_ccb_t *)scb->ccb;
19911da177e4SLinus Torvalds 	epthru	= ccb->epthru;
19921da177e4SLinus Torvalds 	channel	= scb->dev_channel;
19931da177e4SLinus Torvalds 	target	= scb->dev_target;
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds 	// 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout
19961da177e4SLinus Torvalds 	epthru->timeout		= 4;
19971da177e4SLinus Torvalds 	epthru->ars		= 1;
19981da177e4SLinus Torvalds 	epthru->islogical	= 0;
19991da177e4SLinus Torvalds 	epthru->channel		= 0;
20001da177e4SLinus Torvalds 	epthru->target		= (channel << 4) | target;
20011da177e4SLinus Torvalds 	epthru->logdrv		= SCP2LUN(scp);
20021da177e4SLinus Torvalds 	epthru->reqsenselen	= 14;
20031da177e4SLinus Torvalds 	epthru->cdblen		= scp->cmd_len;
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds 	memcpy(epthru->cdb, scp->cmnd, scp->cmd_len);
20061da177e4SLinus Torvalds 
200732fbac22SFUJITA Tomonori 	if (scsi_bufflen(scp)) {
200832fbac22SFUJITA Tomonori 		epthru->dataxferlen	= scsi_bufflen(scp);
20091da177e4SLinus Torvalds 		epthru->dataxferaddr	= ccb->sgl_dma_h;
20101da177e4SLinus Torvalds 		epthru->numsge		= megaraid_mbox_mksgl(adapter, scb);
20111da177e4SLinus Torvalds 	}
20121da177e4SLinus Torvalds 	else {
20131da177e4SLinus Torvalds 		epthru->dataxferaddr	= 0;
20141da177e4SLinus Torvalds 		epthru->dataxferlen	= 0;
20151da177e4SLinus Torvalds 		epthru->numsge		= 0;
20161da177e4SLinus Torvalds 	}
20171da177e4SLinus Torvalds 	return;
20181da177e4SLinus Torvalds }
20191da177e4SLinus Torvalds 
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds /**
20221da177e4SLinus Torvalds  * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs
2023a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
20241da177e4SLinus Torvalds  *
2025a69b74d3SRandy Dunlap  * Interrupt acknowledgement sequence for memory mapped HBAs. Find out the
20261da177e4SLinus Torvalds  * completed command and put them on the completed list for later processing.
20271da177e4SLinus Torvalds  *
20281da177e4SLinus Torvalds  * Returns:	1 if the interrupt is valid, 0 otherwise
20291da177e4SLinus Torvalds  */
2030858119e1SArjan van de Ven static int
megaraid_ack_sequence(adapter_t * adapter)20311da177e4SLinus Torvalds megaraid_ack_sequence(adapter_t *adapter)
20321da177e4SLinus Torvalds {
20331da177e4SLinus Torvalds 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
20341da177e4SLinus Torvalds 	mbox_t			*mbox;
20351da177e4SLinus Torvalds 	scb_t			*scb;
20361da177e4SLinus Torvalds 	uint8_t			nstatus;
20371da177e4SLinus Torvalds 	uint8_t			completed[MBOX_MAX_FIRMWARE_STATUS];
20381da177e4SLinus Torvalds 	struct list_head	clist;
20391da177e4SLinus Torvalds 	int			handled;
20401da177e4SLinus Torvalds 	uint32_t		dword;
20411da177e4SLinus Torvalds 	unsigned long		flags;
20421da177e4SLinus Torvalds 	int			i, j;
20431da177e4SLinus Torvalds 
20441da177e4SLinus Torvalds 
20451da177e4SLinus Torvalds 	mbox	= raid_dev->mbox;
20461da177e4SLinus Torvalds 
20471da177e4SLinus Torvalds 	// move the SCBs from the firmware completed array to our local list
20481da177e4SLinus Torvalds 	INIT_LIST_HEAD(&clist);
20491da177e4SLinus Torvalds 
20501da177e4SLinus Torvalds 	// loop till F/W has more commands for us to complete
20511da177e4SLinus Torvalds 	handled = 0;
20521da177e4SLinus Torvalds 	spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
20531da177e4SLinus Torvalds 	do {
20541da177e4SLinus Torvalds 		/*
20551da177e4SLinus Torvalds 		 * Check if a valid interrupt is pending. If found, force the
20561da177e4SLinus Torvalds 		 * interrupt line low.
20571da177e4SLinus Torvalds 		 */
20581da177e4SLinus Torvalds 		dword = RDOUTDOOR(raid_dev);
20591da177e4SLinus Torvalds 		if (dword != 0x10001234) break;
20601da177e4SLinus Torvalds 
20611da177e4SLinus Torvalds 		handled = 1;
20621da177e4SLinus Torvalds 
20631da177e4SLinus Torvalds 		WROUTDOOR(raid_dev, 0x10001234);
20641da177e4SLinus Torvalds 
20651da177e4SLinus Torvalds 		nstatus = 0;
20661da177e4SLinus Torvalds 		// wait for valid numstatus to post
20671da177e4SLinus Torvalds 		for (i = 0; i < 0xFFFFF; i++) {
20681da177e4SLinus Torvalds 			if (mbox->numstatus != 0xFF) {
20691da177e4SLinus Torvalds 				nstatus = mbox->numstatus;
20701da177e4SLinus Torvalds 				break;
20711da177e4SLinus Torvalds 			}
20721da177e4SLinus Torvalds 			rmb();
20731da177e4SLinus Torvalds 		}
20741da177e4SLinus Torvalds 		mbox->numstatus = 0xFF;
20751da177e4SLinus Torvalds 
20761da177e4SLinus Torvalds 		adapter->outstanding_cmds -= nstatus;
20771da177e4SLinus Torvalds 
20781da177e4SLinus Torvalds 		for (i = 0; i < nstatus; i++) {
20791da177e4SLinus Torvalds 
20801da177e4SLinus Torvalds 			// wait for valid command index to post
20811da177e4SLinus Torvalds 			for (j = 0; j < 0xFFFFF; j++) {
20821da177e4SLinus Torvalds 				if (mbox->completed[i] != 0xFF) break;
20831da177e4SLinus Torvalds 				rmb();
20841da177e4SLinus Torvalds 			}
20851da177e4SLinus Torvalds 			completed[i]		= mbox->completed[i];
20861da177e4SLinus Torvalds 			mbox->completed[i]	= 0xFF;
20871da177e4SLinus Torvalds 
20881da177e4SLinus Torvalds 			if (completed[i] == 0xFF) {
20891da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_CRIT
20901da177e4SLinus Torvalds 				"megaraid: command posting timed out\n"));
20911da177e4SLinus Torvalds 
20921da177e4SLinus Torvalds 				BUG();
20931da177e4SLinus Torvalds 				continue;
20941da177e4SLinus Torvalds 			}
20951da177e4SLinus Torvalds 
20961da177e4SLinus Torvalds 			// Get SCB associated with this command id
20971da177e4SLinus Torvalds 			if (completed[i] >= MBOX_MAX_SCSI_CMDS) {
20981da177e4SLinus Torvalds 				// a cmm command
20991da177e4SLinus Torvalds 				scb = adapter->uscb_list + (completed[i] -
21001da177e4SLinus Torvalds 						MBOX_MAX_SCSI_CMDS);
21011da177e4SLinus Torvalds 			}
21021da177e4SLinus Torvalds 			else {
21031da177e4SLinus Torvalds 				// an os command
21041da177e4SLinus Torvalds 				scb = adapter->kscb_list + completed[i];
21051da177e4SLinus Torvalds 			}
21061da177e4SLinus Torvalds 
21071da177e4SLinus Torvalds 			scb->status = mbox->status;
21081da177e4SLinus Torvalds 			list_add_tail(&scb->list, &clist);
21091da177e4SLinus Torvalds 		}
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 		// Acknowledge interrupt
21121da177e4SLinus Torvalds 		WRINDOOR(raid_dev, 0x02);
21131da177e4SLinus Torvalds 
21141da177e4SLinus Torvalds 	} while(1);
21151da177e4SLinus Torvalds 
21161da177e4SLinus Torvalds 	spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
21171da177e4SLinus Torvalds 
21181da177e4SLinus Torvalds 
21191da177e4SLinus Torvalds 	// put the completed commands in the completed list. DPC would
21201da177e4SLinus Torvalds 	// complete these commands later
21211da177e4SLinus Torvalds 	spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
21221da177e4SLinus Torvalds 
21231da177e4SLinus Torvalds 	list_splice(&clist, &adapter->completed_list);
21241da177e4SLinus Torvalds 
21251da177e4SLinus Torvalds 	spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
21261da177e4SLinus Torvalds 
21271da177e4SLinus Torvalds 
21281da177e4SLinus Torvalds 	// schedule the DPC if there is some work for it
21291da177e4SLinus Torvalds 	if (handled)
21301da177e4SLinus Torvalds 		tasklet_schedule(&adapter->dpc_h);
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds 	return handled;
21331da177e4SLinus Torvalds }
21341da177e4SLinus Torvalds 
21351da177e4SLinus Torvalds 
21361da177e4SLinus Torvalds /**
21371da177e4SLinus Torvalds  * megaraid_isr - isr for memory based mailbox based controllers
2138a69b74d3SRandy Dunlap  * @irq		: irq
2139a69b74d3SRandy Dunlap  * @devp	: pointer to our soft state
21401da177e4SLinus Torvalds  *
21411da177e4SLinus Torvalds  * Interrupt service routine for memory-mapped mailbox controllers.
21421da177e4SLinus Torvalds  */
21431da177e4SLinus Torvalds static irqreturn_t
megaraid_isr(int irq,void * devp)21447d12e780SDavid Howells megaraid_isr(int irq, void *devp)
21451da177e4SLinus Torvalds {
21461da177e4SLinus Torvalds 	adapter_t	*adapter = devp;
21471da177e4SLinus Torvalds 	int		handled;
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds 	handled = megaraid_ack_sequence(adapter);
21501da177e4SLinus Torvalds 
21511da177e4SLinus Torvalds 	/* Loop through any pending requests */
21521da177e4SLinus Torvalds 	if (!adapter->quiescent) {
21531da177e4SLinus Torvalds 		megaraid_mbox_runpendq(adapter, NULL);
21541da177e4SLinus Torvalds 	}
21551da177e4SLinus Torvalds 
21561da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
21571da177e4SLinus Torvalds }
21581da177e4SLinus Torvalds 
21591da177e4SLinus Torvalds 
21601da177e4SLinus Torvalds /**
21611da177e4SLinus Torvalds  * megaraid_mbox_dpc - the tasklet to complete the commands from completed list
21621da177e4SLinus Torvalds  * @devp	: pointer to HBA soft state
21631da177e4SLinus Torvalds  *
21641da177e4SLinus Torvalds  * Pick up the commands from the completed list and send back to the owners.
21651da177e4SLinus Torvalds  * This is a reentrant function and does not assume any locks are held while
21661da177e4SLinus Torvalds  * it is being called.
21671da177e4SLinus Torvalds  */
21681da177e4SLinus Torvalds static void
megaraid_mbox_dpc(unsigned long devp)21691da177e4SLinus Torvalds megaraid_mbox_dpc(unsigned long devp)
21701da177e4SLinus Torvalds {
21711da177e4SLinus Torvalds 	adapter_t		*adapter = (adapter_t *)devp;
21721da177e4SLinus Torvalds 	mraid_device_t		*raid_dev;
21731da177e4SLinus Torvalds 	struct list_head	clist;
21741da177e4SLinus Torvalds 	struct scatterlist	*sgl;
21751da177e4SLinus Torvalds 	scb_t			*scb;
21761da177e4SLinus Torvalds 	scb_t			*tmp;
21771da177e4SLinus Torvalds 	struct scsi_cmnd	*scp;
21781da177e4SLinus Torvalds 	mraid_passthru_t	*pthru;
21791da177e4SLinus Torvalds 	mraid_epassthru_t	*epthru;
21801da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
21811da177e4SLinus Torvalds 	int			islogical;
21821da177e4SLinus Torvalds 	int			pdev_index;
21831da177e4SLinus Torvalds 	int			pdev_state;
21841da177e4SLinus Torvalds 	mbox_t			*mbox;
21851da177e4SLinus Torvalds 	unsigned long		flags;
21861da177e4SLinus Torvalds 	uint8_t			c;
21871da177e4SLinus Torvalds 	int			status;
2188c005fb4fSJu, Seokmann 	uioc_t			*kioc;
21891da177e4SLinus Torvalds 
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds 	if (!adapter) return;
21921da177e4SLinus Torvalds 
21931da177e4SLinus Torvalds 	raid_dev = ADAP2RAIDDEV(adapter);
21941da177e4SLinus Torvalds 
21951da177e4SLinus Torvalds 	// move the SCBs from the completed list to our local list
21961da177e4SLinus Torvalds 	INIT_LIST_HEAD(&clist);
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 	spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
21991da177e4SLinus Torvalds 
22001da177e4SLinus Torvalds 	list_splice_init(&adapter->completed_list, &clist);
22011da177e4SLinus Torvalds 
22021da177e4SLinus Torvalds 	spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
22031da177e4SLinus Torvalds 
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds 	list_for_each_entry_safe(scb, tmp, &clist, list) {
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds 		status		= scb->status;
22081da177e4SLinus Torvalds 		scp		= scb->scp;
22091da177e4SLinus Torvalds 		ccb		= (mbox_ccb_t *)scb->ccb;
22101da177e4SLinus Torvalds 		pthru		= ccb->pthru;
22111da177e4SLinus Torvalds 		epthru		= ccb->epthru;
22121da177e4SLinus Torvalds 		mbox		= ccb->mbox;
22131da177e4SLinus Torvalds 
22141da177e4SLinus Torvalds 		// Make sure f/w has completed a valid command
22151da177e4SLinus Torvalds 		if (scb->state != SCB_ISSUED) {
22161da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_CRIT
22171da177e4SLinus Torvalds 			"megaraid critical err: invalid command %d:%d:%p\n",
22181da177e4SLinus Torvalds 				scb->sno, scb->state, scp));
22191da177e4SLinus Torvalds 			BUG();
22201da177e4SLinus Torvalds 			continue;	// Must never happen!
22211da177e4SLinus Torvalds 		}
22221da177e4SLinus Torvalds 
22231da177e4SLinus Torvalds 		// check for the management command and complete it right away
22241da177e4SLinus Torvalds 		if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
22251da177e4SLinus Torvalds 			scb->state	= SCB_FREE;
22261da177e4SLinus Torvalds 			scb->status	= status;
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds 			// remove from local clist
22291da177e4SLinus Torvalds 			list_del_init(&scb->list);
22301da177e4SLinus Torvalds 
2231c005fb4fSJu, Seokmann 			kioc			= (uioc_t *)scb->gp;
2232c005fb4fSJu, Seokmann 			kioc->status		= 0;
2233c005fb4fSJu, Seokmann 
22341da177e4SLinus Torvalds 			megaraid_mbox_mm_done(adapter, scb);
22351da177e4SLinus Torvalds 
22361da177e4SLinus Torvalds 			continue;
22371da177e4SLinus Torvalds 		}
22381da177e4SLinus Torvalds 
22391da177e4SLinus Torvalds 		// Was an abort issued for this command earlier
22401da177e4SLinus Torvalds 		if (scb->state & SCB_ABORT) {
22411da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
22425cd049a5SChristoph Hellwig 			"megaraid: aborted cmd [%x] completed\n",
22435cd049a5SChristoph Hellwig 				scb->sno));
22441da177e4SLinus Torvalds 		}
22451da177e4SLinus Torvalds 
22461da177e4SLinus Torvalds 		/*
22471da177e4SLinus Torvalds 		 * If the inquiry came of a disk drive which is not part of
22481da177e4SLinus Torvalds 		 * any RAID array, expose it to the kernel. For this to be
22491da177e4SLinus Torvalds 		 * enabled, user must set the "megaraid_expose_unconf_disks"
22501da177e4SLinus Torvalds 		 * flag to 1 by specifying it on module parameter list.
22511da177e4SLinus Torvalds 		 * This would enable data migration off drives from other
22521da177e4SLinus Torvalds 		 * configurations.
22531da177e4SLinus Torvalds 		 */
22541da177e4SLinus Torvalds 		islogical = MRAID_IS_LOGICAL(adapter, scp);
22551da177e4SLinus Torvalds 		if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0
22561da177e4SLinus Torvalds 				&& IS_RAID_CH(raid_dev, scb->dev_channel)) {
22571da177e4SLinus Torvalds 
225832fbac22SFUJITA Tomonori 			sgl = scsi_sglist(scp);
225945711f1aSJens Axboe 			if (sg_page(sgl)) {
226045711f1aSJens Axboe 				c = *(unsigned char *) sg_virt(&sgl[0]);
226132fbac22SFUJITA Tomonori 			} else {
22621da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_WARNING
22631da177e4SLinus Torvalds 						 "megaraid mailbox: invalid sg:%d\n",
22641da177e4SLinus Torvalds 						 __LINE__));
22651da177e4SLinus Torvalds 				c = 0;
22661da177e4SLinus Torvalds 			}
22671da177e4SLinus Torvalds 
22681da177e4SLinus Torvalds 			if ((c & 0x1F ) == TYPE_DISK) {
22691da177e4SLinus Torvalds 				pdev_index = (scb->dev_channel * 16) +
22701da177e4SLinus Torvalds 					scb->dev_target;
22711da177e4SLinus Torvalds 				pdev_state =
22721da177e4SLinus Torvalds 					raid_dev->pdrv_state[pdev_index] & 0x0F;
22731da177e4SLinus Torvalds 
22741da177e4SLinus Torvalds 				if (pdev_state == PDRV_ONLINE		||
22751da177e4SLinus Torvalds 					pdev_state == PDRV_FAILED	||
22761da177e4SLinus Torvalds 					pdev_state == PDRV_RBLD		||
22771da177e4SLinus Torvalds 					pdev_state == PDRV_HOTSPARE	||
22781da177e4SLinus Torvalds 					megaraid_expose_unconf_disks == 0) {
22791da177e4SLinus Torvalds 
22801da177e4SLinus Torvalds 					status = 0xF0;
22811da177e4SLinus Torvalds 				}
22821da177e4SLinus Torvalds 			}
22831da177e4SLinus Torvalds 		}
22841da177e4SLinus Torvalds 
22851da177e4SLinus Torvalds 		// Convert MegaRAID status to Linux error code
22861da177e4SLinus Torvalds 		switch (status) {
22871da177e4SLinus Torvalds 
22881da177e4SLinus Torvalds 		case 0x00:
22891da177e4SLinus Torvalds 
22901da177e4SLinus Torvalds 			scp->result = (DID_OK << 16);
22911da177e4SLinus Torvalds 			break;
22921da177e4SLinus Torvalds 
22931da177e4SLinus Torvalds 		case 0x02:
22941da177e4SLinus Torvalds 
22951da177e4SLinus Torvalds 			/* set sense_buffer and result fields */
22961da177e4SLinus Torvalds 			if (mbox->cmd == MBOXCMD_PASSTHRU ||
22971da177e4SLinus Torvalds 				mbox->cmd == MBOXCMD_PASSTHRU64) {
22981da177e4SLinus Torvalds 
22991da177e4SLinus Torvalds 				memcpy(scp->sense_buffer, pthru->reqsensearea,
23001da177e4SLinus Torvalds 						14);
23011da177e4SLinus Torvalds 
2302464a00c9SHannes Reinecke 				scp->result = SAM_STAT_CHECK_CONDITION;
23031da177e4SLinus Torvalds 			}
23041da177e4SLinus Torvalds 			else {
23051da177e4SLinus Torvalds 				if (mbox->cmd == MBOXCMD_EXTPTHRU) {
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 					memcpy(scp->sense_buffer,
23081da177e4SLinus Torvalds 						epthru->reqsensearea, 14);
23091da177e4SLinus Torvalds 
2310464a00c9SHannes Reinecke 					scp->result = SAM_STAT_CHECK_CONDITION;
2311f2b1e9c6SHannes Reinecke 				} else
2312f2b1e9c6SHannes Reinecke 					scsi_build_sense(scp, 0,
2313f2b1e9c6SHannes Reinecke 							 ABORTED_COMMAND, 0, 0);
23141da177e4SLinus Torvalds 			}
23151da177e4SLinus Torvalds 			break;
23161da177e4SLinus Torvalds 
23171da177e4SLinus Torvalds 		case 0x08:
23181da177e4SLinus Torvalds 
23191da177e4SLinus Torvalds 			scp->result = DID_BUS_BUSY << 16 | status;
23201da177e4SLinus Torvalds 			break;
23211da177e4SLinus Torvalds 
23221da177e4SLinus Torvalds 		default:
23231da177e4SLinus Torvalds 
23241da177e4SLinus Torvalds 			/*
23251da177e4SLinus Torvalds 			 * If TEST_UNIT_READY fails, we know RESERVATION_STATUS
23261da177e4SLinus Torvalds 			 * failed
23271da177e4SLinus Torvalds 			 */
23281da177e4SLinus Torvalds 			if (scp->cmnd[0] == TEST_UNIT_READY) {
23291da177e4SLinus Torvalds 				scp->result = DID_ERROR << 16 |
23303d45cefcSHannes Reinecke 					SAM_STAT_RESERVATION_CONFLICT;
23311da177e4SLinus Torvalds 			}
23321da177e4SLinus Torvalds 			else
23331da177e4SLinus Torvalds 			/*
23341da177e4SLinus Torvalds 			 * Error code returned is 1 if Reserve or Release
23351da177e4SLinus Torvalds 			 * failed or the input parameter is invalid
23361da177e4SLinus Torvalds 			 */
23371da177e4SLinus Torvalds 			if (status == 1 && (scp->cmnd[0] == RESERVE ||
23381da177e4SLinus Torvalds 					 scp->cmnd[0] == RELEASE)) {
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds 				scp->result = DID_ERROR << 16 |
23413d45cefcSHannes Reinecke 					SAM_STAT_RESERVATION_CONFLICT;
23421da177e4SLinus Torvalds 			}
23431da177e4SLinus Torvalds 			else {
23441da177e4SLinus Torvalds 				scp->result = DID_BAD_TARGET << 16 | status;
23451da177e4SLinus Torvalds 			}
23461da177e4SLinus Torvalds 		}
23471da177e4SLinus Torvalds 
23481da177e4SLinus Torvalds 		// print a debug message for all failed commands
23491da177e4SLinus Torvalds 		if (status) {
23501da177e4SLinus Torvalds 			megaraid_mbox_display_scb(adapter, scb);
23511da177e4SLinus Torvalds 		}
23521da177e4SLinus Torvalds 
235367d98f0aSChristoph Hellwig 		scsi_dma_unmap(scp);
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 		// remove from local clist
23561da177e4SLinus Torvalds 		list_del_init(&scb->list);
23571da177e4SLinus Torvalds 
23581da177e4SLinus Torvalds 		// put back in free list
23591da177e4SLinus Torvalds 		megaraid_dealloc_scb(adapter, scb);
23601da177e4SLinus Torvalds 
23611da177e4SLinus Torvalds 		// send the scsi packet back to kernel
2362f1170b83SBart Van Assche 		scsi_done(scp);
23631da177e4SLinus Torvalds 	}
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds 	return;
23661da177e4SLinus Torvalds }
23671da177e4SLinus Torvalds 
23681da177e4SLinus Torvalds 
23691da177e4SLinus Torvalds /**
23701da177e4SLinus Torvalds  * megaraid_abort_handler - abort the scsi command
23711da177e4SLinus Torvalds  * @scp		: command to be aborted
23721da177e4SLinus Torvalds  *
23731da177e4SLinus Torvalds  * Abort a previous SCSI request. Only commands on the pending list can be
23741da177e4SLinus Torvalds  * aborted. All the commands issued to the F/W must complete.
23751da177e4SLinus Torvalds  **/
23761da177e4SLinus Torvalds static int
megaraid_abort_handler(struct scsi_cmnd * scp)2377f2c8dc40SChristoph Hellwig megaraid_abort_handler(struct scsi_cmnd *scp)
23781da177e4SLinus Torvalds {
23791da177e4SLinus Torvalds 	adapter_t		*adapter;
23801da177e4SLinus Torvalds 	mraid_device_t		*raid_dev;
23811da177e4SLinus Torvalds 	scb_t			*scb;
23821da177e4SLinus Torvalds 	scb_t			*tmp;
23831da177e4SLinus Torvalds 	int			found;
23841da177e4SLinus Torvalds 	unsigned long		flags;
23851da177e4SLinus Torvalds 	int			i;
23861da177e4SLinus Torvalds 
23871da177e4SLinus Torvalds 
23881da177e4SLinus Torvalds 	adapter		= SCP2ADAPTER(scp);
23891da177e4SLinus Torvalds 	raid_dev	= ADAP2RAIDDEV(adapter);
23901da177e4SLinus Torvalds 
23911da177e4SLinus Torvalds 	con_log(CL_ANN, (KERN_WARNING
23925cd049a5SChristoph Hellwig 		"megaraid: aborting cmd=%x <c=%d t=%d l=%d>\n",
23935cd049a5SChristoph Hellwig 		scp->cmnd[0], SCP2CHANNEL(scp),
23941da177e4SLinus Torvalds 		SCP2TARGET(scp), SCP2LUN(scp)));
23951da177e4SLinus Torvalds 
23961da177e4SLinus Torvalds 	// If FW has stopped responding, simply return failure
23971da177e4SLinus Torvalds 	if (raid_dev->hw_error) {
23981da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_NOTICE
23991da177e4SLinus Torvalds 			"megaraid: hw error, not aborting\n"));
24001da177e4SLinus Torvalds 		return FAILED;
24011da177e4SLinus Torvalds 	}
24021da177e4SLinus Torvalds 
24031da177e4SLinus Torvalds 	// There might a race here, where the command was completed by the
24041da177e4SLinus Torvalds 	// firmware and now it is on the completed list. Before we could
24051da177e4SLinus Torvalds 	// complete the command to the kernel in dpc, the abort came.
24061da177e4SLinus Torvalds 	// Find out if this is the case to avoid the race.
24071da177e4SLinus Torvalds 	scb = NULL;
24081da177e4SLinus Torvalds 	spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
24091da177e4SLinus Torvalds 	list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) {
24101da177e4SLinus Torvalds 
24111da177e4SLinus Torvalds 		if (scb->scp == scp) {	// Found command
24121da177e4SLinus Torvalds 
24131da177e4SLinus Torvalds 			list_del_init(&scb->list);	// from completed list
24141da177e4SLinus Torvalds 
24151da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_WARNING
24165cd049a5SChristoph Hellwig 			"megaraid: %d[%d:%d], abort from completed list\n",
24175cd049a5SChristoph Hellwig 				scb->sno, scb->dev_channel, scb->dev_target));
24181da177e4SLinus Torvalds 
24191da177e4SLinus Torvalds 			scp->result = (DID_ABORT << 16);
2420f1170b83SBart Van Assche 			scsi_done(scp);
24211da177e4SLinus Torvalds 
24221da177e4SLinus Torvalds 			megaraid_dealloc_scb(adapter, scb);
24231da177e4SLinus Torvalds 
24241da177e4SLinus Torvalds 			spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter),
24251da177e4SLinus Torvalds 				flags);
24261da177e4SLinus Torvalds 
24271da177e4SLinus Torvalds 			return SUCCESS;
24281da177e4SLinus Torvalds 		}
24291da177e4SLinus Torvalds 	}
24301da177e4SLinus Torvalds 	spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
24311da177e4SLinus Torvalds 
24321da177e4SLinus Torvalds 
24331da177e4SLinus Torvalds 	// Find out if this command is still on the pending list. If it is and
24341da177e4SLinus Torvalds 	// was never issued, abort and return success. If the command is owned
24351da177e4SLinus Torvalds 	// by the firmware, we must wait for it to complete by the FW.
24361da177e4SLinus Torvalds 	spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
24371da177e4SLinus Torvalds 	list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
24381da177e4SLinus Torvalds 
24391da177e4SLinus Torvalds 		if (scb->scp == scp) {	// Found command
24401da177e4SLinus Torvalds 
24411da177e4SLinus Torvalds 			list_del_init(&scb->list);	// from pending list
24421da177e4SLinus Torvalds 
24431da177e4SLinus Torvalds 			ASSERT(!(scb->state & SCB_ISSUED));
24441da177e4SLinus Torvalds 
24451da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_WARNING
24465cd049a5SChristoph Hellwig 				"megaraid abort: [%d:%d], driver owner\n",
24475cd049a5SChristoph Hellwig 				scb->dev_channel, scb->dev_target));
24481da177e4SLinus Torvalds 
24491da177e4SLinus Torvalds 			scp->result = (DID_ABORT << 16);
2450f1170b83SBart Van Assche 			scsi_done(scp);
24511da177e4SLinus Torvalds 
24521da177e4SLinus Torvalds 			megaraid_dealloc_scb(adapter, scb);
24531da177e4SLinus Torvalds 
24541da177e4SLinus Torvalds 			spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
24551da177e4SLinus Torvalds 				flags);
24561da177e4SLinus Torvalds 
24571da177e4SLinus Torvalds 			return SUCCESS;
24581da177e4SLinus Torvalds 		}
24591da177e4SLinus Torvalds 	}
24601da177e4SLinus Torvalds 	spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
24611da177e4SLinus Torvalds 
24621da177e4SLinus Torvalds 
24631da177e4SLinus Torvalds 	// Check do we even own this command, in which case this would be
24641da177e4SLinus Torvalds 	// owned by the firmware. The only way to locate the FW scb is to
24651da177e4SLinus Torvalds 	// traverse through the list of all SCB, since driver does not
24661da177e4SLinus Torvalds 	// maintain these SCBs on any list
24671da177e4SLinus Torvalds 	found = 0;
2468f2c8dc40SChristoph Hellwig 	spin_lock_irq(&adapter->lock);
24691da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
24701da177e4SLinus Torvalds 		scb = adapter->kscb_list + i;
24711da177e4SLinus Torvalds 
24721da177e4SLinus Torvalds 		if (scb->scp == scp) {
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds 			found = 1;
24751da177e4SLinus Torvalds 
24761da177e4SLinus Torvalds 			if (!(scb->state & SCB_ISSUED)) {
24771da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_WARNING
24785cd049a5SChristoph Hellwig 				"megaraid abort: %d[%d:%d], invalid state\n",
24795cd049a5SChristoph Hellwig 				scb->sno, scb->dev_channel, scb->dev_target));
24801da177e4SLinus Torvalds 				BUG();
24811da177e4SLinus Torvalds 			}
24821da177e4SLinus Torvalds 			else {
24831da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_WARNING
24845cd049a5SChristoph Hellwig 				"megaraid abort: %d[%d:%d], fw owner\n",
24855cd049a5SChristoph Hellwig 				scb->sno, scb->dev_channel, scb->dev_target));
24861da177e4SLinus Torvalds 			}
24871da177e4SLinus Torvalds 		}
24881da177e4SLinus Torvalds 	}
2489f2c8dc40SChristoph Hellwig 	spin_unlock_irq(&adapter->lock);
24901da177e4SLinus Torvalds 
24911da177e4SLinus Torvalds 	if (!found) {
24925cd049a5SChristoph Hellwig 		con_log(CL_ANN, (KERN_WARNING "megaraid abort: do now own\n"));
24931da177e4SLinus Torvalds 
24941da177e4SLinus Torvalds 		// FIXME: Should there be a callback for this command?
24951da177e4SLinus Torvalds 		return SUCCESS;
24961da177e4SLinus Torvalds 	}
24971da177e4SLinus Torvalds 
24981da177e4SLinus Torvalds 	// We cannot actually abort a command owned by firmware, return
24991da177e4SLinus Torvalds 	// failure and wait for reset. In host reset handler, we will find out
25001da177e4SLinus Torvalds 	// if the HBA is still live
25011da177e4SLinus Torvalds 	return FAILED;
25021da177e4SLinus Torvalds }
25031da177e4SLinus Torvalds 
25041da177e4SLinus Torvalds /**
25053948ff8bSMatthias Schid  * megaraid_reset_handler - device reset handler for mailbox based driver
25061da177e4SLinus Torvalds  * @scp		: reference command
25071da177e4SLinus Torvalds  *
25081da177e4SLinus Torvalds  * Reset handler for the mailbox based controller. First try to find out if
25091da177e4SLinus Torvalds  * the FW is still live, in which case the outstanding commands counter mut go
25101da177e4SLinus Torvalds  * down to 0. If that happens, also issue the reservation reset command to
25111da177e4SLinus Torvalds  * relinquish (possible) reservations on the logical drives connected to this
2512a69b74d3SRandy Dunlap  * host.
25131da177e4SLinus Torvalds  **/
25141da177e4SLinus Torvalds static int
megaraid_reset_handler(struct scsi_cmnd * scp)2515f2c8dc40SChristoph Hellwig megaraid_reset_handler(struct scsi_cmnd *scp)
25161da177e4SLinus Torvalds {
25171da177e4SLinus Torvalds 	adapter_t	*adapter;
25181da177e4SLinus Torvalds 	scb_t		*scb;
25191da177e4SLinus Torvalds 	scb_t		*tmp;
25201da177e4SLinus Torvalds 	mraid_device_t	*raid_dev;
25211da177e4SLinus Torvalds 	unsigned long	flags;
25221da177e4SLinus Torvalds 	uint8_t		raw_mbox[sizeof(mbox_t)];
25231da177e4SLinus Torvalds 	int		rval;
25241da177e4SLinus Torvalds 	int		recovery_window;
25251da177e4SLinus Torvalds 	int		i;
2526c005fb4fSJu, Seokmann 	uioc_t		*kioc;
25271da177e4SLinus Torvalds 
25281da177e4SLinus Torvalds 	adapter		= SCP2ADAPTER(scp);
25291da177e4SLinus Torvalds 	raid_dev	= ADAP2RAIDDEV(adapter);
25301da177e4SLinus Torvalds 
25311da177e4SLinus Torvalds 	// return failure if adapter is not responding
25321da177e4SLinus Torvalds 	if (raid_dev->hw_error) {
25331da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_NOTICE
25341da177e4SLinus Torvalds 			"megaraid: hw error, cannot reset\n"));
25351da177e4SLinus Torvalds 		return FAILED;
25361da177e4SLinus Torvalds 	}
25371da177e4SLinus Torvalds 
25381da177e4SLinus Torvalds 	// Under exceptional conditions, FW can take up to 3 minutes to
25391da177e4SLinus Torvalds 	// complete command processing. Wait for additional 2 minutes for the
25401da177e4SLinus Torvalds 	// pending commands counter to go down to 0. If it doesn't, let the
25411da177e4SLinus Torvalds 	// controller be marked offline
25421da177e4SLinus Torvalds 	// Also, reset all the commands currently owned by the driver
25431da177e4SLinus Torvalds 	spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
25441da177e4SLinus Torvalds 	list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
25451da177e4SLinus Torvalds 		list_del_init(&scb->list);	// from pending list
25461da177e4SLinus Torvalds 
2547c005fb4fSJu, Seokmann 		if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
2548c005fb4fSJu, Seokmann 			con_log(CL_ANN, (KERN_WARNING
2549c005fb4fSJu, Seokmann 			"megaraid: IOCTL packet with %d[%d:%d] being reset\n",
2550c005fb4fSJu, Seokmann 			scb->sno, scb->dev_channel, scb->dev_target));
2551c005fb4fSJu, Seokmann 
2552c005fb4fSJu, Seokmann 			scb->status = -1;
2553c005fb4fSJu, Seokmann 
2554c005fb4fSJu, Seokmann 			kioc			= (uioc_t *)scb->gp;
2555c005fb4fSJu, Seokmann 			kioc->status		= -EFAULT;
2556c005fb4fSJu, Seokmann 
2557c005fb4fSJu, Seokmann 			megaraid_mbox_mm_done(adapter, scb);
2558c005fb4fSJu, Seokmann 		} else {
2559c005fb4fSJu, Seokmann 			if (scb->scp == scp) {	// Found command
25601da177e4SLinus Torvalds 				con_log(CL_ANN, (KERN_WARNING
25615cd049a5SChristoph Hellwig 					"megaraid: %d[%d:%d], reset from pending list\n",
25625cd049a5SChristoph Hellwig 					scb->sno, scb->dev_channel, scb->dev_target));
2563c005fb4fSJu, Seokmann 			} else {
2564c005fb4fSJu, Seokmann 				con_log(CL_ANN, (KERN_WARNING
2565c005fb4fSJu, Seokmann 				"megaraid: IO packet with %d[%d:%d] being reset\n",
2566c005fb4fSJu, Seokmann 				scb->sno, scb->dev_channel, scb->dev_target));
2567c005fb4fSJu, Seokmann 			}
25681da177e4SLinus Torvalds 
2569c005fb4fSJu, Seokmann 			scb->scp->result = (DID_RESET << 16);
2570f1170b83SBart Van Assche 			scsi_done(scb->scp);
25711da177e4SLinus Torvalds 
25721da177e4SLinus Torvalds 			megaraid_dealloc_scb(adapter, scb);
25731da177e4SLinus Torvalds 		}
2574c005fb4fSJu, Seokmann 	}
25751da177e4SLinus Torvalds 	spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
25761da177e4SLinus Torvalds 
25771da177e4SLinus Torvalds 	if (adapter->outstanding_cmds) {
25781da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_NOTICE
25791da177e4SLinus Torvalds 			"megaraid: %d outstanding commands. Max wait %d sec\n",
2580c005fb4fSJu, Seokmann 			adapter->outstanding_cmds,
2581c005fb4fSJu, Seokmann 			(MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT)));
25821da177e4SLinus Torvalds 	}
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds 	recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
25851da177e4SLinus Torvalds 
2586c005fb4fSJu, Seokmann 	for (i = 0; i < recovery_window; i++) {
25871da177e4SLinus Torvalds 
25881da177e4SLinus Torvalds 		megaraid_ack_sequence(adapter);
25891da177e4SLinus Torvalds 
25901da177e4SLinus Torvalds 		// print a message once every 5 seconds only
25911da177e4SLinus Torvalds 		if (!(i % 5)) {
25921da177e4SLinus Torvalds 			con_log(CL_ANN, (
25931da177e4SLinus Torvalds 			"megaraid mbox: Wait for %d commands to complete:%d\n",
25941da177e4SLinus Torvalds 				adapter->outstanding_cmds,
2595c005fb4fSJu, Seokmann 				(MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i));
25961da177e4SLinus Torvalds 		}
25971da177e4SLinus Torvalds 
259825985edcSLucas De Marchi 		// bailout if no recovery happened in reset time
2599c005fb4fSJu, Seokmann 		if (adapter->outstanding_cmds == 0) {
26001da177e4SLinus Torvalds 			break;
26011da177e4SLinus Torvalds 		}
26021da177e4SLinus Torvalds 
26031da177e4SLinus Torvalds 		msleep(1000);
26041da177e4SLinus Torvalds 	}
26051da177e4SLinus Torvalds 
2606f2c8dc40SChristoph Hellwig 	spin_lock(&adapter->lock);
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds 	// If still outstanding commands, bail out
26091da177e4SLinus Torvalds 	if (adapter->outstanding_cmds) {
26101da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
26111da177e4SLinus Torvalds 			"megaraid mbox: critical hardware error!\n"));
26121da177e4SLinus Torvalds 
26131da177e4SLinus Torvalds 		raid_dev->hw_error = 1;
26141da177e4SLinus Torvalds 
2615f2c8dc40SChristoph Hellwig 		rval = FAILED;
2616f2c8dc40SChristoph Hellwig 		goto out;
26171da177e4SLinus Torvalds 	}
26181da177e4SLinus Torvalds 	else {
26191da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_NOTICE
2620af901ca1SAndré Goddard Rosa 		"megaraid mbox: reset sequence completed successfully\n"));
26211da177e4SLinus Torvalds 	}
26221da177e4SLinus Torvalds 
26231da177e4SLinus Torvalds 
26241da177e4SLinus Torvalds 	// If the controller supports clustering, reset reservations
2625f2c8dc40SChristoph Hellwig 	if (!adapter->ha) {
2626f2c8dc40SChristoph Hellwig 		rval = SUCCESS;
2627f2c8dc40SChristoph Hellwig 		goto out;
2628f2c8dc40SChristoph Hellwig 	}
26291da177e4SLinus Torvalds 
26301da177e4SLinus Torvalds 	// clear reservations if any
26311da177e4SLinus Torvalds 	raw_mbox[0] = CLUSTER_CMD;
26321da177e4SLinus Torvalds 	raw_mbox[2] = RESET_RESERVATIONS;
26331da177e4SLinus Torvalds 
26341da177e4SLinus Torvalds 	rval = SUCCESS;
26351da177e4SLinus Torvalds 	if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) {
26361da177e4SLinus Torvalds 		con_log(CL_ANN,
26371da177e4SLinus Torvalds 			(KERN_INFO "megaraid: reservation reset\n"));
26381da177e4SLinus Torvalds 	}
26391da177e4SLinus Torvalds 	else {
26401da177e4SLinus Torvalds 		rval = FAILED;
26411da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
26421da177e4SLinus Torvalds 				"megaraid: reservation reset failed\n"));
26431da177e4SLinus Torvalds 	}
26441da177e4SLinus Torvalds 
2645f2c8dc40SChristoph Hellwig  out:
26466548b0e5SDan Carpenter 	spin_unlock(&adapter->lock);
26471da177e4SLinus Torvalds 	return rval;
26481da177e4SLinus Torvalds }
26491da177e4SLinus Torvalds 
26501da177e4SLinus Torvalds /*
26511da177e4SLinus Torvalds  * START: internal commands library
26521da177e4SLinus Torvalds  *
26531da177e4SLinus Torvalds  * This section of the driver has the common routine used by the driver and
26541da177e4SLinus Torvalds  * also has all the FW routines
26551da177e4SLinus Torvalds  */
26561da177e4SLinus Torvalds 
26571da177e4SLinus Torvalds /**
26581da177e4SLinus Torvalds  * mbox_post_sync_cmd() - blocking command to the mailbox based controllers
2659a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
2660a69b74d3SRandy Dunlap  * @raw_mbox	: the mailbox
26611da177e4SLinus Torvalds  *
26621da177e4SLinus Torvalds  * Issue a scb in synchronous and non-interrupt mode for mailbox based
2663a69b74d3SRandy Dunlap  * controllers.
26641da177e4SLinus Torvalds  */
26651da177e4SLinus Torvalds static int
mbox_post_sync_cmd(adapter_t * adapter,uint8_t raw_mbox[])26661da177e4SLinus Torvalds mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[])
26671da177e4SLinus Torvalds {
26681da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
26691da177e4SLinus Torvalds 	mbox_t		*mbox;
26701da177e4SLinus Torvalds 	uint8_t		status;
26711da177e4SLinus Torvalds 	int		i;
26721da177e4SLinus Torvalds 
26731da177e4SLinus Torvalds 	mbox	= raid_dev->mbox;
26741da177e4SLinus Torvalds 
26751da177e4SLinus Torvalds 	/*
26761da177e4SLinus Torvalds 	 * Wait until mailbox is free
26771da177e4SLinus Torvalds 	 */
26781da177e4SLinus Torvalds 	if (megaraid_busywait_mbox(raid_dev) != 0)
26791da177e4SLinus Torvalds 		goto blocked_mailbox;
26801da177e4SLinus Torvalds 
26811da177e4SLinus Torvalds 	/*
26821da177e4SLinus Torvalds 	 * Copy mailbox data into host structure
26831da177e4SLinus Torvalds 	 */
26841da177e4SLinus Torvalds 	memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
26851da177e4SLinus Torvalds 	mbox->cmdid		= 0xFE;
26861da177e4SLinus Torvalds 	mbox->busy		= 1;
26871da177e4SLinus Torvalds 	mbox->poll		= 0;
26881da177e4SLinus Torvalds 	mbox->ack		= 0;
26891da177e4SLinus Torvalds 	mbox->numstatus		= 0xFF;
26901da177e4SLinus Torvalds 	mbox->status		= 0xFF;
26911da177e4SLinus Torvalds 
26921da177e4SLinus Torvalds 	wmb();
26931da177e4SLinus Torvalds 	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
26941da177e4SLinus Torvalds 
26951da177e4SLinus Torvalds 	// wait for maximum 1 second for status to post. If the status is not
26961da177e4SLinus Torvalds 	// available within 1 second, assume FW is initializing and wait
26971da177e4SLinus Torvalds 	// for an extended amount of time
26981da177e4SLinus Torvalds 	if (mbox->numstatus == 0xFF) {	// status not yet available
269953b3531bSAlexey Dobriyan 		udelay(25);
27001da177e4SLinus Torvalds 
27011da177e4SLinus Torvalds 		for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) {
27021da177e4SLinus Torvalds 			rmb();
27031da177e4SLinus Torvalds 			msleep(1);
27041da177e4SLinus Torvalds 		}
27051da177e4SLinus Torvalds 
27061da177e4SLinus Torvalds 
27071da177e4SLinus Torvalds 		if (i == 1000) {
27081da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
27091da177e4SLinus Torvalds 				"megaraid mailbox: wait for FW to boot      "));
27101da177e4SLinus Torvalds 
27111da177e4SLinus Torvalds 			for (i = 0; (mbox->numstatus == 0xFF) &&
27121da177e4SLinus Torvalds 					(i < MBOX_RESET_WAIT); i++) {
27131da177e4SLinus Torvalds 				rmb();
27141da177e4SLinus Torvalds 				con_log(CL_ANN, ("\b\b\b\b\b[%03d]",
27151da177e4SLinus Torvalds 							MBOX_RESET_WAIT - i));
27161da177e4SLinus Torvalds 				msleep(1000);
27171da177e4SLinus Torvalds 			}
27181da177e4SLinus Torvalds 
27191da177e4SLinus Torvalds 			if (i == MBOX_RESET_WAIT) {
27201da177e4SLinus Torvalds 
27211da177e4SLinus Torvalds 				con_log(CL_ANN, (
27221da177e4SLinus Torvalds 				"\nmegaraid mailbox: status not available\n"));
27231da177e4SLinus Torvalds 
27241da177e4SLinus Torvalds 				return -1;
27251da177e4SLinus Torvalds 			}
27261da177e4SLinus Torvalds 			con_log(CL_ANN, ("\b\b\b\b\b[ok] \n"));
27271da177e4SLinus Torvalds 		}
27281da177e4SLinus Torvalds 	}
27291da177e4SLinus Torvalds 
27301da177e4SLinus Torvalds 	// wait for maximum 1 second for poll semaphore
27311da177e4SLinus Torvalds 	if (mbox->poll != 0x77) {
27321da177e4SLinus Torvalds 		udelay(25);
27331da177e4SLinus Torvalds 
27341da177e4SLinus Torvalds 		for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) {
27351da177e4SLinus Torvalds 			rmb();
27361da177e4SLinus Torvalds 			msleep(1);
27371da177e4SLinus Torvalds 		}
27381da177e4SLinus Torvalds 
27391da177e4SLinus Torvalds 		if (i == 1000) {
27401da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_WARNING
27411da177e4SLinus Torvalds 			"megaraid mailbox: could not get poll semaphore\n"));
27421da177e4SLinus Torvalds 			return -1;
27431da177e4SLinus Torvalds 		}
27441da177e4SLinus Torvalds 	}
27451da177e4SLinus Torvalds 
27461da177e4SLinus Torvalds 	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
27471da177e4SLinus Torvalds 	wmb();
27481da177e4SLinus Torvalds 
27491da177e4SLinus Torvalds 	// wait for maximum 1 second for acknowledgement
27501da177e4SLinus Torvalds 	if (RDINDOOR(raid_dev) & 0x2) {
27511da177e4SLinus Torvalds 		udelay(25);
27521da177e4SLinus Torvalds 
27531da177e4SLinus Torvalds 		for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) {
27541da177e4SLinus Torvalds 			rmb();
27551da177e4SLinus Torvalds 			msleep(1);
27561da177e4SLinus Torvalds 		}
27571da177e4SLinus Torvalds 
27581da177e4SLinus Torvalds 		if (i == 1000) {
27591da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_WARNING
27601da177e4SLinus Torvalds 				"megaraid mailbox: could not acknowledge\n"));
27611da177e4SLinus Torvalds 			return -1;
27621da177e4SLinus Torvalds 		}
27631da177e4SLinus Torvalds 	}
27641da177e4SLinus Torvalds 	mbox->poll	= 0;
27651da177e4SLinus Torvalds 	mbox->ack	= 0x77;
27661da177e4SLinus Torvalds 
27671da177e4SLinus Torvalds 	status = mbox->status;
27681da177e4SLinus Torvalds 
27691da177e4SLinus Torvalds 	// invalidate the completed command id array. After command
27701da177e4SLinus Torvalds 	// completion, firmware would write the valid id.
27711da177e4SLinus Torvalds 	mbox->numstatus	= 0xFF;
27721da177e4SLinus Torvalds 	mbox->status	= 0xFF;
27731da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) {
27741da177e4SLinus Torvalds 		mbox->completed[i] = 0xFF;
27751da177e4SLinus Torvalds 	}
27761da177e4SLinus Torvalds 
27771da177e4SLinus Torvalds 	return status;
27781da177e4SLinus Torvalds 
27791da177e4SLinus Torvalds blocked_mailbox:
27801da177e4SLinus Torvalds 
27811da177e4SLinus Torvalds 	con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") );
27821da177e4SLinus Torvalds 	return -1;
27831da177e4SLinus Torvalds }
27841da177e4SLinus Torvalds 
27851da177e4SLinus Torvalds 
27861da177e4SLinus Torvalds /**
27871da177e4SLinus Torvalds  * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers
2788a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
2789a69b74d3SRandy Dunlap  * @raw_mbox	: the mailbox
27901da177e4SLinus Torvalds  *
27911da177e4SLinus Torvalds  * Issue a scb in synchronous and non-interrupt mode for mailbox based
27921da177e4SLinus Torvalds  * controllers. This is a faster version of the synchronous command and
2793a69b74d3SRandy Dunlap  * therefore can be called in interrupt-context as well.
27941da177e4SLinus Torvalds  */
27951da177e4SLinus Torvalds static int
mbox_post_sync_cmd_fast(adapter_t * adapter,uint8_t raw_mbox[])27961da177e4SLinus Torvalds mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
27971da177e4SLinus Torvalds {
27981da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
27991da177e4SLinus Torvalds 	mbox_t		*mbox;
28001da177e4SLinus Torvalds 	long		i;
28011da177e4SLinus Torvalds 
28021da177e4SLinus Torvalds 
28031da177e4SLinus Torvalds 	mbox	= raid_dev->mbox;
28041da177e4SLinus Torvalds 
28051da177e4SLinus Torvalds 	// return immediately if the mailbox is busy
28061da177e4SLinus Torvalds 	if (mbox->busy) return -1;
28071da177e4SLinus Torvalds 
28081da177e4SLinus Torvalds 	// Copy mailbox data into host structure
28091da177e4SLinus Torvalds 	memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14);
28101da177e4SLinus Torvalds 	mbox->cmdid		= 0xFE;
28111da177e4SLinus Torvalds 	mbox->busy		= 1;
28121da177e4SLinus Torvalds 	mbox->poll		= 0;
28131da177e4SLinus Torvalds 	mbox->ack		= 0;
28141da177e4SLinus Torvalds 	mbox->numstatus		= 0xFF;
28151da177e4SLinus Torvalds 	mbox->status		= 0xFF;
28161da177e4SLinus Torvalds 
28171da177e4SLinus Torvalds 	wmb();
28181da177e4SLinus Torvalds 	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
28191da177e4SLinus Torvalds 
2820c005fb4fSJu, Seokmann 	for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) {
28211da177e4SLinus Torvalds 		if (mbox->numstatus != 0xFF) break;
2822ed7e8ef7SJu, Seokmann 		rmb();
2823c005fb4fSJu, Seokmann 		udelay(MBOX_SYNC_DELAY_200);
28241da177e4SLinus Torvalds 	}
28251da177e4SLinus Torvalds 
2826c005fb4fSJu, Seokmann 	if (i == MBOX_SYNC_WAIT_CNT) {
28271da177e4SLinus Torvalds 		// We may need to re-calibrate the counter
28281da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_CRIT
28291da177e4SLinus Torvalds 			"megaraid: fast sync command timed out\n"));
28301da177e4SLinus Torvalds 	}
28311da177e4SLinus Torvalds 
28321da177e4SLinus Torvalds 	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
28331da177e4SLinus Torvalds 	wmb();
28341da177e4SLinus Torvalds 
28351da177e4SLinus Torvalds 	return mbox->status;
28361da177e4SLinus Torvalds }
28371da177e4SLinus Torvalds 
28381da177e4SLinus Torvalds 
28391da177e4SLinus Torvalds /**
28401da177e4SLinus Torvalds  * megaraid_busywait_mbox() - Wait until the controller's mailbox is available
2841a69b74d3SRandy Dunlap  * @raid_dev	: RAID device (HBA) soft state
28421da177e4SLinus Torvalds  *
2843a69b74d3SRandy Dunlap  * Wait until the controller's mailbox is available to accept more commands.
2844a69b74d3SRandy Dunlap  * Wait for at most 1 second.
28451da177e4SLinus Torvalds  */
28461da177e4SLinus Torvalds static int
megaraid_busywait_mbox(mraid_device_t * raid_dev)28471da177e4SLinus Torvalds megaraid_busywait_mbox(mraid_device_t *raid_dev)
28481da177e4SLinus Torvalds {
28491da177e4SLinus Torvalds 	mbox_t	*mbox = raid_dev->mbox;
28501da177e4SLinus Torvalds 	int	i = 0;
28511da177e4SLinus Torvalds 
28521da177e4SLinus Torvalds 	if (mbox->busy) {
28531da177e4SLinus Torvalds 		udelay(25);
28541da177e4SLinus Torvalds 		for (i = 0; mbox->busy && i < 1000; i++)
28551da177e4SLinus Torvalds 			msleep(1);
28561da177e4SLinus Torvalds 	}
28571da177e4SLinus Torvalds 
28581da177e4SLinus Torvalds 	if (i < 1000) return 0;
28591da177e4SLinus Torvalds 	else return -1;
28601da177e4SLinus Torvalds }
28611da177e4SLinus Torvalds 
28621da177e4SLinus Torvalds 
28631da177e4SLinus Torvalds /**
28641da177e4SLinus Torvalds  * megaraid_mbox_product_info - some static information about the controller
2865a69b74d3SRandy Dunlap  * @adapter	: our soft state
28661da177e4SLinus Torvalds  *
2867a69b74d3SRandy Dunlap  * Issue commands to the controller to grab some parameters required by our
28681da177e4SLinus Torvalds  * caller.
28691da177e4SLinus Torvalds  */
28701da177e4SLinus Torvalds static int
megaraid_mbox_product_info(adapter_t * adapter)28711da177e4SLinus Torvalds megaraid_mbox_product_info(adapter_t *adapter)
28721da177e4SLinus Torvalds {
28731da177e4SLinus Torvalds 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
28741da177e4SLinus Torvalds 	mbox_t			*mbox;
28751da177e4SLinus Torvalds 	uint8_t			raw_mbox[sizeof(mbox_t)];
28761da177e4SLinus Torvalds 	mraid_pinfo_t		*pinfo;
28771da177e4SLinus Torvalds 	dma_addr_t		pinfo_dma_h;
28781da177e4SLinus Torvalds 	mraid_inquiry3_t	*mraid_inq3;
28791da177e4SLinus Torvalds 	int			i;
28801da177e4SLinus Torvalds 
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
28831da177e4SLinus Torvalds 	mbox = (mbox_t *)raw_mbox;
28841da177e4SLinus Torvalds 
28851da177e4SLinus Torvalds 	/*
28861da177e4SLinus Torvalds 	 * Issue an ENQUIRY3 command to find out certain adapter parameters,
28871da177e4SLinus Torvalds 	 * e.g., max channels, max commands etc.
28881da177e4SLinus Torvalds 	 */
2889750afb08SLuis Chamberlain 	pinfo = dma_alloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t),
289066e3a241SChristoph Hellwig 				   &pinfo_dma_h, GFP_KERNEL);
28911da177e4SLinus Torvalds 	if (pinfo == NULL) {
28921da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
2893cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
28941da177e4SLinus Torvalds 			__LINE__));
28951da177e4SLinus Torvalds 
28961da177e4SLinus Torvalds 		return -1;
28971da177e4SLinus Torvalds 	}
28981da177e4SLinus Torvalds 
28991da177e4SLinus Torvalds 	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
29001da177e4SLinus Torvalds 	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
29011da177e4SLinus Torvalds 
29021da177e4SLinus Torvalds 	raw_mbox[0] = FC_NEW_CONFIG;
29031da177e4SLinus Torvalds 	raw_mbox[2] = NC_SUBOP_ENQUIRY3;
29041da177e4SLinus Torvalds 	raw_mbox[3] = ENQ3_GET_SOLICITED_FULL;
29051da177e4SLinus Torvalds 
29061da177e4SLinus Torvalds 	// Issue the command
29071da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
29081da177e4SLinus Torvalds 
29091da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n"));
29101da177e4SLinus Torvalds 
291166e3a241SChristoph Hellwig 		dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t),
29121da177e4SLinus Torvalds 			pinfo, pinfo_dma_h);
29131da177e4SLinus Torvalds 
29141da177e4SLinus Torvalds 		return -1;
29151da177e4SLinus Torvalds 	}
29161da177e4SLinus Torvalds 
29171da177e4SLinus Torvalds 	/*
29181da177e4SLinus Torvalds 	 * Collect information about state of each physical drive
29191da177e4SLinus Torvalds 	 * attached to the controller. We will expose all the disks
29201da177e4SLinus Torvalds 	 * which are not part of RAID
29211da177e4SLinus Torvalds 	 */
29221da177e4SLinus Torvalds 	mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf;
29231da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) {
29241da177e4SLinus Torvalds 		raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i];
29251da177e4SLinus Torvalds 	}
29261da177e4SLinus Torvalds 
29271da177e4SLinus Torvalds 	/*
29281da177e4SLinus Torvalds 	 * Get product info for information like number of channels,
29291da177e4SLinus Torvalds 	 * maximum commands supported.
29301da177e4SLinus Torvalds 	 */
29311da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
29321da177e4SLinus Torvalds 	mbox->xferaddr = (uint32_t)pinfo_dma_h;
29331da177e4SLinus Torvalds 
29341da177e4SLinus Torvalds 	raw_mbox[0] = FC_NEW_CONFIG;
29351da177e4SLinus Torvalds 	raw_mbox[2] = NC_SUBOP_PRODUCT_INFO;
29361da177e4SLinus Torvalds 
29371da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
29381da177e4SLinus Torvalds 
29391da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
29401da177e4SLinus Torvalds 			"megaraid: product info failed\n"));
29411da177e4SLinus Torvalds 
294266e3a241SChristoph Hellwig 		dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t),
29431da177e4SLinus Torvalds 			pinfo, pinfo_dma_h);
29441da177e4SLinus Torvalds 
29451da177e4SLinus Torvalds 		return -1;
29461da177e4SLinus Torvalds 	}
29471da177e4SLinus Torvalds 
29481da177e4SLinus Torvalds 	/*
29491da177e4SLinus Torvalds 	 * Setup some parameters for host, as required by our caller
29501da177e4SLinus Torvalds 	 */
29511da177e4SLinus Torvalds 	adapter->max_channel = pinfo->nchannels;
29521da177e4SLinus Torvalds 
29531da177e4SLinus Torvalds 	/*
29541da177e4SLinus Torvalds 	 * we will export all the logical drives on a single channel.
29551da177e4SLinus Torvalds 	 * Add 1 since inquires do not come for inititor ID
29561da177e4SLinus Torvalds 	 */
29571da177e4SLinus Torvalds 	adapter->max_target	= MAX_LOGICAL_DRIVES_40LD + 1;
29581da177e4SLinus Torvalds 	adapter->max_lun	= 8;	// up to 8 LUNs for non-disk devices
29591da177e4SLinus Torvalds 
29601da177e4SLinus Torvalds 	/*
29611da177e4SLinus Torvalds 	 * These are the maximum outstanding commands for the scsi-layer
29621da177e4SLinus Torvalds 	 */
29631da177e4SLinus Torvalds 	adapter->max_cmds	= MBOX_MAX_SCSI_CMDS;
29641da177e4SLinus Torvalds 
29651da177e4SLinus Torvalds 	memset(adapter->fw_version, 0, VERSION_SIZE);
29661da177e4SLinus Torvalds 	memset(adapter->bios_version, 0, VERSION_SIZE);
29671da177e4SLinus Torvalds 
29681da177e4SLinus Torvalds 	memcpy(adapter->fw_version, pinfo->fw_version, 4);
29691da177e4SLinus Torvalds 	adapter->fw_version[4] = 0;
29701da177e4SLinus Torvalds 
29711da177e4SLinus Torvalds 	memcpy(adapter->bios_version, pinfo->bios_version, 4);
29721da177e4SLinus Torvalds 	adapter->bios_version[4] = 0;
29731da177e4SLinus Torvalds 
29741da177e4SLinus Torvalds 	con_log(CL_ANN, (KERN_NOTICE
29751da177e4SLinus Torvalds 		"megaraid: fw version:[%s] bios version:[%s]\n",
29761da177e4SLinus Torvalds 		adapter->fw_version, adapter->bios_version));
29771da177e4SLinus Torvalds 
297866e3a241SChristoph Hellwig 	dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo,
29791da177e4SLinus Torvalds 			pinfo_dma_h);
29801da177e4SLinus Torvalds 
29811da177e4SLinus Torvalds 	return 0;
29821da177e4SLinus Torvalds }
29831da177e4SLinus Torvalds 
29841da177e4SLinus Torvalds 
29851da177e4SLinus Torvalds 
29861da177e4SLinus Torvalds /**
29871da177e4SLinus Torvalds  * megaraid_mbox_extended_cdb - check for support for extended CDBs
2988a69b74d3SRandy Dunlap  * @adapter	: soft state for the controller
29891da177e4SLinus Torvalds  *
2990a69b74d3SRandy Dunlap  * This routine check whether the controller in question supports extended
2991a69b74d3SRandy Dunlap  * ( > 10 bytes ) CDBs.
29921da177e4SLinus Torvalds  */
29931da177e4SLinus Torvalds static int
megaraid_mbox_extended_cdb(adapter_t * adapter)29941da177e4SLinus Torvalds megaraid_mbox_extended_cdb(adapter_t *adapter)
29951da177e4SLinus Torvalds {
29961da177e4SLinus Torvalds 	mbox_t		*mbox;
29971da177e4SLinus Torvalds 	uint8_t		raw_mbox[sizeof(mbox_t)];
29981da177e4SLinus Torvalds 	int		rval;
29991da177e4SLinus Torvalds 
30001da177e4SLinus Torvalds 	mbox = (mbox_t *)raw_mbox;
30011da177e4SLinus Torvalds 
30021da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
30031da177e4SLinus Torvalds 	mbox->xferaddr	= (uint32_t)adapter->ibuf_dma_h;
30041da177e4SLinus Torvalds 
30051da177e4SLinus Torvalds 	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
30061da177e4SLinus Torvalds 
30071da177e4SLinus Torvalds 	raw_mbox[0] = MAIN_MISC_OPCODE;
30081da177e4SLinus Torvalds 	raw_mbox[2] = SUPPORT_EXT_CDB;
30091da177e4SLinus Torvalds 
30101da177e4SLinus Torvalds 	/*
30111da177e4SLinus Torvalds 	 * Issue the command
30121da177e4SLinus Torvalds 	 */
30131da177e4SLinus Torvalds 	rval = 0;
30141da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
30151da177e4SLinus Torvalds 		rval = -1;
30161da177e4SLinus Torvalds 	}
30171da177e4SLinus Torvalds 
30181da177e4SLinus Torvalds 	return rval;
30191da177e4SLinus Torvalds }
30201da177e4SLinus Torvalds 
30211da177e4SLinus Torvalds 
30221da177e4SLinus Torvalds /**
30231da177e4SLinus Torvalds  * megaraid_mbox_support_ha - Do we support clustering
3024a69b74d3SRandy Dunlap  * @adapter	: soft state for the controller
3025a69b74d3SRandy Dunlap  * @init_id	: ID of the initiator
30261da177e4SLinus Torvalds  *
30271da177e4SLinus Torvalds  * Determine if the firmware supports clustering and the ID of the initiator.
30281da177e4SLinus Torvalds  */
30291da177e4SLinus Torvalds static int
megaraid_mbox_support_ha(adapter_t * adapter,uint16_t * init_id)30301da177e4SLinus Torvalds megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id)
30311da177e4SLinus Torvalds {
30321da177e4SLinus Torvalds 	mbox_t		*mbox;
30331da177e4SLinus Torvalds 	uint8_t		raw_mbox[sizeof(mbox_t)];
30341da177e4SLinus Torvalds 	int		rval;
30351da177e4SLinus Torvalds 
30361da177e4SLinus Torvalds 
30371da177e4SLinus Torvalds 	mbox = (mbox_t *)raw_mbox;
30381da177e4SLinus Torvalds 
30391da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
30401da177e4SLinus Torvalds 
30411da177e4SLinus Torvalds 	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
30421da177e4SLinus Torvalds 
30431da177e4SLinus Torvalds 	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
30441da177e4SLinus Torvalds 
30451da177e4SLinus Torvalds 	raw_mbox[0] = GET_TARGET_ID;
30461da177e4SLinus Torvalds 
30471da177e4SLinus Torvalds 	// Issue the command
30481da177e4SLinus Torvalds 	*init_id = 7;
30491da177e4SLinus Torvalds 	rval =  -1;
30501da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
30511da177e4SLinus Torvalds 
30521da177e4SLinus Torvalds 		*init_id = *(uint8_t *)adapter->ibuf;
30531da177e4SLinus Torvalds 
30541da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_INFO
30551da177e4SLinus Torvalds 			"megaraid: cluster firmware, initiator ID: %d\n",
30561da177e4SLinus Torvalds 			*init_id));
30571da177e4SLinus Torvalds 
30581da177e4SLinus Torvalds 		rval =  0;
30591da177e4SLinus Torvalds 	}
30601da177e4SLinus Torvalds 
30611da177e4SLinus Torvalds 	return rval;
30621da177e4SLinus Torvalds }
30631da177e4SLinus Torvalds 
30641da177e4SLinus Torvalds 
30651da177e4SLinus Torvalds /**
30661da177e4SLinus Torvalds  * megaraid_mbox_support_random_del - Do we support random deletion
3067a69b74d3SRandy Dunlap  * @adapter	: soft state for the controller
30681da177e4SLinus Torvalds  *
3069a69b74d3SRandy Dunlap  * Determine if the firmware supports random deletion.
30701da177e4SLinus Torvalds  * Return:	1 is operation supported, 0 otherwise
30711da177e4SLinus Torvalds  */
30721da177e4SLinus Torvalds static int
megaraid_mbox_support_random_del(adapter_t * adapter)30731da177e4SLinus Torvalds megaraid_mbox_support_random_del(adapter_t *adapter)
30741da177e4SLinus Torvalds {
30751da177e4SLinus Torvalds 	uint8_t		raw_mbox[sizeof(mbox_t)];
30761da177e4SLinus Torvalds 	int		rval;
30771da177e4SLinus Torvalds 
307869cd39e9SHannes Reinecke 	/*
307969cd39e9SHannes Reinecke 	 * Newer firmware on Dell CERC expect a different
308069cd39e9SHannes Reinecke 	 * random deletion handling, so disable it.
308169cd39e9SHannes Reinecke 	 */
308269cd39e9SHannes Reinecke 	if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI &&
308369cd39e9SHannes Reinecke 	    adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 &&
308469cd39e9SHannes Reinecke 	    adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
308569cd39e9SHannes Reinecke 	    adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH &&
308669cd39e9SHannes Reinecke 	    (adapter->fw_version[0] > '6' ||
308769cd39e9SHannes Reinecke 	     (adapter->fw_version[0] == '6' &&
308869cd39e9SHannes Reinecke 	      adapter->fw_version[2] > '6') ||
308969cd39e9SHannes Reinecke 	     (adapter->fw_version[0] == '6'
309069cd39e9SHannes Reinecke 	      && adapter->fw_version[2] == '6'
309169cd39e9SHannes Reinecke 	      && adapter->fw_version[3] > '1'))) {
309269cd39e9SHannes Reinecke 		con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n"));
309369cd39e9SHannes Reinecke 		return 0;
309469cd39e9SHannes Reinecke 	}
30951da177e4SLinus Torvalds 
30961da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
30971da177e4SLinus Torvalds 
30981da177e4SLinus Torvalds 	raw_mbox[0] = FC_DEL_LOGDRV;
30991da177e4SLinus Torvalds 	raw_mbox[2] = OP_SUP_DEL_LOGDRV;
31001da177e4SLinus Torvalds 
31011da177e4SLinus Torvalds 	// Issue the command
31021da177e4SLinus Torvalds 	rval = 0;
31031da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
31041da177e4SLinus Torvalds 
31051da177e4SLinus Torvalds 		con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n"));
31061da177e4SLinus Torvalds 
31071da177e4SLinus Torvalds 		rval =  1;
31081da177e4SLinus Torvalds 	}
31091da177e4SLinus Torvalds 
31101da177e4SLinus Torvalds 	return rval;
31111da177e4SLinus Torvalds }
31121da177e4SLinus Torvalds 
31131da177e4SLinus Torvalds 
31141da177e4SLinus Torvalds /**
31151da177e4SLinus Torvalds  * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware
3116a69b74d3SRandy Dunlap  * @adapter	: soft state for the controller
31171da177e4SLinus Torvalds  *
31181da177e4SLinus Torvalds  * Find out the maximum number of scatter-gather elements supported by the
3119a69b74d3SRandy Dunlap  * firmware.
31201da177e4SLinus Torvalds  */
31211da177e4SLinus Torvalds static int
megaraid_mbox_get_max_sg(adapter_t * adapter)31221da177e4SLinus Torvalds megaraid_mbox_get_max_sg(adapter_t *adapter)
31231da177e4SLinus Torvalds {
31241da177e4SLinus Torvalds 	mbox_t		*mbox;
31251da177e4SLinus Torvalds 	uint8_t		raw_mbox[sizeof(mbox_t)];
31261da177e4SLinus Torvalds 	int		nsg;
31271da177e4SLinus Torvalds 
31281da177e4SLinus Torvalds 
31291da177e4SLinus Torvalds 	mbox = (mbox_t *)raw_mbox;
31301da177e4SLinus Torvalds 
31311da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
31321da177e4SLinus Torvalds 
31331da177e4SLinus Torvalds 	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
31341da177e4SLinus Torvalds 
31351da177e4SLinus Torvalds 	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
31361da177e4SLinus Torvalds 
31371da177e4SLinus Torvalds 	raw_mbox[0] = MAIN_MISC_OPCODE;
31381da177e4SLinus Torvalds 	raw_mbox[2] = GET_MAX_SG_SUPPORT;
31391da177e4SLinus Torvalds 
31401da177e4SLinus Torvalds 	// Issue the command
31411da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
31421da177e4SLinus Torvalds 		nsg =  *(uint8_t *)adapter->ibuf;
31431da177e4SLinus Torvalds 	}
31441da177e4SLinus Torvalds 	else {
31451da177e4SLinus Torvalds 		nsg =  MBOX_DEFAULT_SG_SIZE;
31461da177e4SLinus Torvalds 	}
31471da177e4SLinus Torvalds 
31481da177e4SLinus Torvalds 	if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE;
31491da177e4SLinus Torvalds 
31501da177e4SLinus Torvalds 	return nsg;
31511da177e4SLinus Torvalds }
31521da177e4SLinus Torvalds 
31531da177e4SLinus Torvalds 
31541da177e4SLinus Torvalds /**
31551da177e4SLinus Torvalds  * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels
3156a69b74d3SRandy Dunlap  * @adapter	: soft state for the controller
31571da177e4SLinus Torvalds  *
3158a69b74d3SRandy Dunlap  * Enumerate the RAID and SCSI channels for ROMB platforms so that channels
3159a69b74d3SRandy Dunlap  * can be exported as regular SCSI channels.
31601da177e4SLinus Torvalds  */
31611da177e4SLinus Torvalds static void
megaraid_mbox_enum_raid_scsi(adapter_t * adapter)31621da177e4SLinus Torvalds megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
31631da177e4SLinus Torvalds {
31641da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
31651da177e4SLinus Torvalds 	mbox_t		*mbox;
31661da177e4SLinus Torvalds 	uint8_t		raw_mbox[sizeof(mbox_t)];
31671da177e4SLinus Torvalds 
31681da177e4SLinus Torvalds 
31691da177e4SLinus Torvalds 	mbox = (mbox_t *)raw_mbox;
31701da177e4SLinus Torvalds 
31711da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
31721da177e4SLinus Torvalds 
31731da177e4SLinus Torvalds 	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
31741da177e4SLinus Torvalds 
31751da177e4SLinus Torvalds 	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
31761da177e4SLinus Torvalds 
31771da177e4SLinus Torvalds 	raw_mbox[0] = CHNL_CLASS;
31781da177e4SLinus Torvalds 	raw_mbox[2] = GET_CHNL_CLASS;
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 	// Issue the command. If the command fails, all channels are RAID
31811da177e4SLinus Torvalds 	// channels
31821da177e4SLinus Torvalds 	raid_dev->channel_class = 0xFF;
31831da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
31841da177e4SLinus Torvalds 		raid_dev->channel_class =  *(uint8_t *)adapter->ibuf;
31851da177e4SLinus Torvalds 	}
31861da177e4SLinus Torvalds 
31871da177e4SLinus Torvalds 	return;
31881da177e4SLinus Torvalds }
31891da177e4SLinus Torvalds 
31901da177e4SLinus Torvalds 
31911da177e4SLinus Torvalds /**
31921da177e4SLinus Torvalds  * megaraid_mbox_flush_cache - flush adapter and disks cache
3193a69b74d3SRandy Dunlap  * @adapter		: soft state for the controller
31941da177e4SLinus Torvalds  *
3195a69b74d3SRandy Dunlap  * Flush adapter cache followed by disks cache.
31961da177e4SLinus Torvalds  */
31971da177e4SLinus Torvalds static void
megaraid_mbox_flush_cache(adapter_t * adapter)31981da177e4SLinus Torvalds megaraid_mbox_flush_cache(adapter_t *adapter)
31991da177e4SLinus Torvalds {
32001da177e4SLinus Torvalds 	uint8_t	raw_mbox[sizeof(mbox_t)];
32011da177e4SLinus Torvalds 
32021da177e4SLinus Torvalds 	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
32031da177e4SLinus Torvalds 
32041da177e4SLinus Torvalds 	raw_mbox[0] = FLUSH_ADAPTER;
32051da177e4SLinus Torvalds 
32061da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
32071da177e4SLinus Torvalds 		con_log(CL_ANN, ("megaraid: flush adapter failed\n"));
32081da177e4SLinus Torvalds 	}
32091da177e4SLinus Torvalds 
32101da177e4SLinus Torvalds 	raw_mbox[0] = FLUSH_SYSTEM;
32111da177e4SLinus Torvalds 
32121da177e4SLinus Torvalds 	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
32131da177e4SLinus Torvalds 		con_log(CL_ANN, ("megaraid: flush disks cache failed\n"));
32141da177e4SLinus Torvalds 	}
32151da177e4SLinus Torvalds 
32161da177e4SLinus Torvalds 	return;
32171da177e4SLinus Torvalds }
32181da177e4SLinus Torvalds 
32191da177e4SLinus Torvalds 
32201da177e4SLinus Torvalds /**
3221cd96d96fSSumant Patro  * megaraid_mbox_fire_sync_cmd - fire the sync cmd
3222a69b74d3SRandy Dunlap  * @adapter		: soft state for the controller
3223cd96d96fSSumant Patro  *
3224a69b74d3SRandy Dunlap  * Clears the pending cmds in FW and reinits its RAID structs.
3225cd96d96fSSumant Patro  */
3226cd96d96fSSumant Patro static int
megaraid_mbox_fire_sync_cmd(adapter_t * adapter)3227cd96d96fSSumant Patro megaraid_mbox_fire_sync_cmd(adapter_t *adapter)
3228cd96d96fSSumant Patro {
3229cd96d96fSSumant Patro 	mbox_t	*mbox;
3230cd96d96fSSumant Patro 	uint8_t	raw_mbox[sizeof(mbox_t)];
3231cd96d96fSSumant Patro 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
3232cd96d96fSSumant Patro 	int	status = 0;
3233cd96d96fSSumant Patro 	int i;
3234cd96d96fSSumant Patro 	uint32_t dword;
3235cd96d96fSSumant Patro 
3236cd96d96fSSumant Patro 	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
3237cd96d96fSSumant Patro 
3238cd96d96fSSumant Patro 	raw_mbox[0] = 0xFF;
3239cd96d96fSSumant Patro 
3240cd96d96fSSumant Patro 	mbox	= raid_dev->mbox;
3241cd96d96fSSumant Patro 
3242cd96d96fSSumant Patro 	/* Wait until mailbox is free */
3243cd96d96fSSumant Patro 	if (megaraid_busywait_mbox(raid_dev) != 0) {
3244cd96d96fSSumant Patro 		status = 1;
3245cd96d96fSSumant Patro 		goto blocked_mailbox;
3246cd96d96fSSumant Patro 	}
3247cd96d96fSSumant Patro 
3248cd96d96fSSumant Patro 	/* Copy mailbox data into host structure */
3249cd96d96fSSumant Patro 	memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
3250cd96d96fSSumant Patro 	mbox->cmdid		= 0xFE;
3251cd96d96fSSumant Patro 	mbox->busy		= 1;
3252cd96d96fSSumant Patro 	mbox->poll		= 0;
3253cd96d96fSSumant Patro 	mbox->ack		= 0;
3254cd96d96fSSumant Patro 	mbox->numstatus		= 0;
3255cd96d96fSSumant Patro 	mbox->status		= 0;
3256cd96d96fSSumant Patro 
3257cd96d96fSSumant Patro 	wmb();
3258cd96d96fSSumant Patro 	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
3259cd96d96fSSumant Patro 
3260cd96d96fSSumant Patro 	/* Wait for maximum 1 min for status to post.
3261cd96d96fSSumant Patro 	 * If the Firmware SUPPORTS the ABOVE COMMAND,
3262cd96d96fSSumant Patro 	 * mbox->cmd will be set to 0
3263cd96d96fSSumant Patro 	 * else
3264cd96d96fSSumant Patro 	 * the firmware will reject the command with
3265cd96d96fSSumant Patro 	 * mbox->numstatus set to 1
3266cd96d96fSSumant Patro 	 */
3267cd96d96fSSumant Patro 
3268cd96d96fSSumant Patro 	i = 0;
3269cd96d96fSSumant Patro 	status = 0;
3270cd96d96fSSumant Patro 	while (!mbox->numstatus && mbox->cmd == 0xFF) {
3271cd96d96fSSumant Patro 		rmb();
3272cd96d96fSSumant Patro 		msleep(1);
3273cd96d96fSSumant Patro 		i++;
3274cd96d96fSSumant Patro 		if (i > 1000 * 60) {
3275cd96d96fSSumant Patro 			status = 1;
3276cd96d96fSSumant Patro 			break;
3277cd96d96fSSumant Patro 		}
3278cd96d96fSSumant Patro 	}
3279cd96d96fSSumant Patro 	if (mbox->numstatus == 1)
3280cd96d96fSSumant Patro 		status = 1; /*cmd not supported*/
3281cd96d96fSSumant Patro 
3282cd96d96fSSumant Patro 	/* Check for interrupt line */
3283cd96d96fSSumant Patro 	dword = RDOUTDOOR(raid_dev);
3284cd96d96fSSumant Patro 	WROUTDOOR(raid_dev, dword);
3285cd96d96fSSumant Patro 	WRINDOOR(raid_dev,2);
3286cd96d96fSSumant Patro 
3287cd96d96fSSumant Patro 	return status;
3288cd96d96fSSumant Patro 
3289cd96d96fSSumant Patro blocked_mailbox:
3290cd96d96fSSumant Patro 	con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n"));
3291cd96d96fSSumant Patro 	return status;
3292cd96d96fSSumant Patro }
3293cd96d96fSSumant Patro 
3294cd96d96fSSumant Patro /**
32951da177e4SLinus Torvalds  * megaraid_mbox_display_scb - display SCB information, mostly debug purposes
3296a69b74d3SRandy Dunlap  * @adapter		: controller's soft state
3297a69b74d3SRandy Dunlap  * @scb			: SCB to be displayed
32981da177e4SLinus Torvalds  *
32991da177e4SLinus Torvalds  * Diplay information about the given SCB iff the current debug level is
3300a69b74d3SRandy Dunlap  * verbose.
33011da177e4SLinus Torvalds  */
33021da177e4SLinus Torvalds static void
megaraid_mbox_display_scb(adapter_t * adapter,scb_t * scb)33031da177e4SLinus Torvalds megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb)
33041da177e4SLinus Torvalds {
33051da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
33061da177e4SLinus Torvalds 	struct scsi_cmnd	*scp;
33071da177e4SLinus Torvalds 	mbox_t			*mbox;
33081da177e4SLinus Torvalds 	int			level;
33091da177e4SLinus Torvalds 	int			i;
33101da177e4SLinus Torvalds 
33111da177e4SLinus Torvalds 
33121da177e4SLinus Torvalds 	ccb	= (mbox_ccb_t *)scb->ccb;
33131da177e4SLinus Torvalds 	scp	= scb->scp;
33141da177e4SLinus Torvalds 	mbox	= ccb->mbox;
33151da177e4SLinus Torvalds 
33161da177e4SLinus Torvalds 	level = CL_DLEVEL3;
33171da177e4SLinus Torvalds 
33181da177e4SLinus Torvalds 	con_log(level, (KERN_NOTICE
33191da177e4SLinus Torvalds 		"megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status,
33201da177e4SLinus Torvalds 		mbox->cmd, scb->sno));
33211da177e4SLinus Torvalds 
33221da177e4SLinus Torvalds 	con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n",
33231da177e4SLinus Torvalds 		mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv,
33241da177e4SLinus Torvalds 		mbox->numsge));
33251da177e4SLinus Torvalds 
33261da177e4SLinus Torvalds 	if (!scp) return;
33271da177e4SLinus Torvalds 
33281da177e4SLinus Torvalds 	con_log(level, (KERN_NOTICE "scsi cmnd: "));
33291da177e4SLinus Torvalds 
33301da177e4SLinus Torvalds 	for (i = 0; i < scp->cmd_len; i++) {
33311da177e4SLinus Torvalds 		con_log(level, ("%#2.02x ", scp->cmnd[i]));
33321da177e4SLinus Torvalds 	}
33331da177e4SLinus Torvalds 
33341da177e4SLinus Torvalds 	con_log(level, ("\n"));
33351da177e4SLinus Torvalds 
33361da177e4SLinus Torvalds 	return;
33371da177e4SLinus Torvalds }
33381da177e4SLinus Torvalds 
33391da177e4SLinus Torvalds 
33401da177e4SLinus Torvalds /**
33411da177e4SLinus Torvalds  * megaraid_mbox_setup_device_map - manage device ids
33421da177e4SLinus Torvalds  * @adapter	: Driver's soft state
33431da177e4SLinus Torvalds  *
33443948ff8bSMatthias Schid  * Manage the device ids to have an appropriate mapping between the kernel
33451da177e4SLinus Torvalds  * scsi addresses and megaraid scsi and logical drive addresses. We export
33461da177e4SLinus Torvalds  * scsi devices on their actual addresses, whereas the logical drives are
33471da177e4SLinus Torvalds  * exported on a virtual scsi channel.
3348a69b74d3SRandy Dunlap  */
33491da177e4SLinus Torvalds static void
megaraid_mbox_setup_device_map(adapter_t * adapter)33501da177e4SLinus Torvalds megaraid_mbox_setup_device_map(adapter_t *adapter)
33511da177e4SLinus Torvalds {
33521da177e4SLinus Torvalds 	uint8_t		c;
33531da177e4SLinus Torvalds 	uint8_t		t;
33541da177e4SLinus Torvalds 
33551da177e4SLinus Torvalds 	/*
33561da177e4SLinus Torvalds 	 * First fill the values on the logical drive channel
33571da177e4SLinus Torvalds 	 */
33581da177e4SLinus Torvalds 	for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
33591da177e4SLinus Torvalds 		adapter->device_ids[adapter->max_channel][t] =
33601da177e4SLinus Torvalds 			(t < adapter->init_id) ?  t : t - 1;
33611da177e4SLinus Torvalds 
33621da177e4SLinus Torvalds 	adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF;
33631da177e4SLinus Torvalds 
33641da177e4SLinus Torvalds 	/*
33651da177e4SLinus Torvalds 	 * Fill the values on the physical devices channels
33661da177e4SLinus Torvalds 	 */
33671da177e4SLinus Torvalds 	for (c = 0; c < adapter->max_channel; c++)
33681da177e4SLinus Torvalds 		for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
33691da177e4SLinus Torvalds 			adapter->device_ids[c][t] = (c << 8) | t;
33701da177e4SLinus Torvalds }
33711da177e4SLinus Torvalds 
33721da177e4SLinus Torvalds 
33731da177e4SLinus Torvalds /*
33741da177e4SLinus Torvalds  * END: internal commands library
33751da177e4SLinus Torvalds  */
33761da177e4SLinus Torvalds 
33771da177e4SLinus Torvalds /*
33781da177e4SLinus Torvalds  * START: Interface for the common management module
33791da177e4SLinus Torvalds  *
3380b1c11812SJoe Perches  * This is the module, which interfaces with the common management module to
33811da177e4SLinus Torvalds  * provide support for ioctl and sysfs
33821da177e4SLinus Torvalds  */
33831da177e4SLinus Torvalds 
33841da177e4SLinus Torvalds /**
3385b1c11812SJoe Perches  * megaraid_cmm_register - register with the management module
3386a69b74d3SRandy Dunlap  * @adapter		: HBA soft state
33871da177e4SLinus Torvalds  *
33881da177e4SLinus Torvalds  * Register with the management module, which allows applications to issue
33891da177e4SLinus Torvalds  * ioctl calls to the drivers. This interface is used by the management module
33901da177e4SLinus Torvalds  * to setup sysfs support as well.
33911da177e4SLinus Torvalds  */
33921da177e4SLinus Torvalds static int
megaraid_cmm_register(adapter_t * adapter)33931da177e4SLinus Torvalds megaraid_cmm_register(adapter_t *adapter)
33941da177e4SLinus Torvalds {
33951da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
33961da177e4SLinus Torvalds 	mraid_mmadp_t	adp;
33971da177e4SLinus Torvalds 	scb_t		*scb;
33981da177e4SLinus Torvalds 	mbox_ccb_t	*ccb;
33991da177e4SLinus Torvalds 	int		rval;
34001da177e4SLinus Torvalds 	int		i;
34011da177e4SLinus Torvalds 
34021da177e4SLinus Torvalds 	// Allocate memory for the base list of scb for management module.
3403dd00cc48SYoann Padioleau 	adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL);
34041da177e4SLinus Torvalds 
34051da177e4SLinus Torvalds 	if (adapter->uscb_list == NULL) {
34061da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
3407cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
34081da177e4SLinus Torvalds 			__LINE__));
34091da177e4SLinus Torvalds 		return -1;
34101da177e4SLinus Torvalds 	}
34111da177e4SLinus Torvalds 
34121da177e4SLinus Torvalds 
34131da177e4SLinus Torvalds 	// Initialize the synchronization parameters for resources for
34141da177e4SLinus Torvalds 	// commands for management module
34151da177e4SLinus Torvalds 	INIT_LIST_HEAD(&adapter->uscb_pool);
34161da177e4SLinus Torvalds 
34171da177e4SLinus Torvalds 	spin_lock_init(USER_FREE_LIST_LOCK(adapter));
34181da177e4SLinus Torvalds 
34191da177e4SLinus Torvalds 
34201da177e4SLinus Torvalds 
34211da177e4SLinus Torvalds 	// link all the packets. Note, CCB for commands, coming from the
34221da177e4SLinus Torvalds 	// commom management module, mailbox physical address are already
34231da177e4SLinus Torvalds 	// setup by it. We just need placeholder for that in our local command
34241da177e4SLinus Torvalds 	// control blocks
34251da177e4SLinus Torvalds 	for (i = 0; i < MBOX_MAX_USER_CMDS; i++) {
34261da177e4SLinus Torvalds 
34271da177e4SLinus Torvalds 		scb			= adapter->uscb_list + i;
34281da177e4SLinus Torvalds 		ccb			= raid_dev->uccb_list + i;
34291da177e4SLinus Torvalds 
34301da177e4SLinus Torvalds 		scb->ccb		= (caddr_t)ccb;
34311da177e4SLinus Torvalds 		ccb->mbox64		= raid_dev->umbox64 + i;
34321da177e4SLinus Torvalds 		ccb->mbox		= &ccb->mbox64->mbox32;
34331da177e4SLinus Torvalds 		ccb->raw_mbox		= (uint8_t *)ccb->mbox;
34341da177e4SLinus Torvalds 
34351da177e4SLinus Torvalds 		scb->gp			= 0;
34361da177e4SLinus Torvalds 
34371da177e4SLinus Torvalds 		// COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR
34381da177e4SLinus Torvalds 		// COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER)
34391da177e4SLinus Torvalds 		scb->sno		= i + MBOX_MAX_SCSI_CMDS;
34401da177e4SLinus Torvalds 
34411da177e4SLinus Torvalds 		scb->scp		= NULL;
34421da177e4SLinus Torvalds 		scb->state		= SCB_FREE;
344366e3a241SChristoph Hellwig 		scb->dma_direction	= DMA_NONE;
34441da177e4SLinus Torvalds 		scb->dma_type		= MRAID_DMA_NONE;
34451da177e4SLinus Torvalds 		scb->dev_channel	= -1;
34461da177e4SLinus Torvalds 		scb->dev_target		= -1;
34471da177e4SLinus Torvalds 
34481da177e4SLinus Torvalds 		// put scb in the free pool
34491da177e4SLinus Torvalds 		list_add_tail(&scb->list, &adapter->uscb_pool);
34501da177e4SLinus Torvalds 	}
34511da177e4SLinus Torvalds 
34521da177e4SLinus Torvalds 	adp.unique_id		= adapter->unique_id;
34531da177e4SLinus Torvalds 	adp.drvr_type		= DRVRTYPE_MBOX;
34541da177e4SLinus Torvalds 	adp.drvr_data		= (unsigned long)adapter;
34551da177e4SLinus Torvalds 	adp.pdev		= adapter->pdev;
34561da177e4SLinus Torvalds 	adp.issue_uioc		= megaraid_mbox_mm_handler;
3457c005fb4fSJu, Seokmann 	adp.timeout		= MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
34581da177e4SLinus Torvalds 	adp.max_kioc		= MBOX_MAX_USER_CMDS;
34591da177e4SLinus Torvalds 
34601da177e4SLinus Torvalds 	if ((rval = mraid_mm_register_adp(&adp)) != 0) {
34611da177e4SLinus Torvalds 
34621da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
34631da177e4SLinus Torvalds 			"megaraid mbox: did not register with CMM\n"));
34641da177e4SLinus Torvalds 
34651da177e4SLinus Torvalds 		kfree(adapter->uscb_list);
34661da177e4SLinus Torvalds 	}
34671da177e4SLinus Torvalds 
34681da177e4SLinus Torvalds 	return rval;
34691da177e4SLinus Torvalds }
34701da177e4SLinus Torvalds 
34711da177e4SLinus Torvalds 
34721da177e4SLinus Torvalds /**
3473b1c11812SJoe Perches  * megaraid_cmm_unregister - un-register with the management module
3474a69b74d3SRandy Dunlap  * @adapter		: HBA soft state
34751da177e4SLinus Torvalds  *
34761da177e4SLinus Torvalds  * Un-register with the management module.
34771da177e4SLinus Torvalds  * FIXME: mgmt module must return failure for unregister if it has pending
3478a69b74d3SRandy Dunlap  * commands in LLD.
34791da177e4SLinus Torvalds  */
34801da177e4SLinus Torvalds static int
megaraid_cmm_unregister(adapter_t * adapter)34811da177e4SLinus Torvalds megaraid_cmm_unregister(adapter_t *adapter)
34821da177e4SLinus Torvalds {
34831da177e4SLinus Torvalds 	kfree(adapter->uscb_list);
34841da177e4SLinus Torvalds 	mraid_mm_unregister_adp(adapter->unique_id);
34851da177e4SLinus Torvalds 	return 0;
34861da177e4SLinus Torvalds }
34871da177e4SLinus Torvalds 
34881da177e4SLinus Torvalds 
34891da177e4SLinus Torvalds /**
34901da177e4SLinus Torvalds  * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD
3491a69b74d3SRandy Dunlap  * @drvr_data		: LLD specific data
3492a69b74d3SRandy Dunlap  * @kioc		: CMM interface packet
3493a69b74d3SRandy Dunlap  * @action		: command action
34941da177e4SLinus Torvalds  *
3495b1c11812SJoe Perches  * This routine is invoked whenever the Common Management Module (CMM) has a
34961da177e4SLinus Torvalds  * command for us. The 'action' parameter specifies if this is a new command
34971da177e4SLinus Torvalds  * or otherwise.
34981da177e4SLinus Torvalds  */
34991da177e4SLinus Torvalds static int
megaraid_mbox_mm_handler(unsigned long drvr_data,uioc_t * kioc,uint32_t action)35001da177e4SLinus Torvalds megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action)
35011da177e4SLinus Torvalds {
35021da177e4SLinus Torvalds 	adapter_t *adapter;
35031da177e4SLinus Torvalds 
35041da177e4SLinus Torvalds 	if (action != IOCTL_ISSUE) {
35051da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
35061da177e4SLinus Torvalds 			"megaraid: unsupported management action:%#2x\n",
35071da177e4SLinus Torvalds 			action));
35081da177e4SLinus Torvalds 		return (-ENOTSUPP);
35091da177e4SLinus Torvalds 	}
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds 	adapter = (adapter_t *)drvr_data;
35121da177e4SLinus Torvalds 
35131da177e4SLinus Torvalds 	// make sure this adapter is not being detached right now.
35141da177e4SLinus Torvalds 	if (atomic_read(&adapter->being_detached)) {
35151da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
35161da177e4SLinus Torvalds 			"megaraid: reject management request, detaching\n"));
35171da177e4SLinus Torvalds 		return (-ENODEV);
35181da177e4SLinus Torvalds 	}
35191da177e4SLinus Torvalds 
35201da177e4SLinus Torvalds 	switch (kioc->opcode) {
35211da177e4SLinus Torvalds 
35221da177e4SLinus Torvalds 	case GET_ADAP_INFO:
35231da177e4SLinus Torvalds 
35241da177e4SLinus Torvalds 		kioc->status =  gather_hbainfo(adapter, (mraid_hba_info_t *)
35251da177e4SLinus Torvalds 					(unsigned long)kioc->buf_vaddr);
35261da177e4SLinus Torvalds 
35271da177e4SLinus Torvalds 		kioc->done(kioc);
35281da177e4SLinus Torvalds 
35291da177e4SLinus Torvalds 		return kioc->status;
35301da177e4SLinus Torvalds 
35311da177e4SLinus Torvalds 	case MBOX_CMD:
35321da177e4SLinus Torvalds 
35331da177e4SLinus Torvalds 		return megaraid_mbox_mm_command(adapter, kioc);
35341da177e4SLinus Torvalds 
35351da177e4SLinus Torvalds 	default:
35361da177e4SLinus Torvalds 		kioc->status = (-EINVAL);
35371da177e4SLinus Torvalds 		kioc->done(kioc);
35381da177e4SLinus Torvalds 		return (-EINVAL);
35391da177e4SLinus Torvalds 	}
35401da177e4SLinus Torvalds 
35411da177e4SLinus Torvalds 	return 0;	// not reached
35421da177e4SLinus Torvalds }
35431da177e4SLinus Torvalds 
35441da177e4SLinus Torvalds /**
35451da177e4SLinus Torvalds  * megaraid_mbox_mm_command - issues commands routed through CMM
3546a69b74d3SRandy Dunlap  * @adapter		: HBA soft state
3547a69b74d3SRandy Dunlap  * @kioc		: management command packet
35481da177e4SLinus Torvalds  *
35491da177e4SLinus Torvalds  * Issues commands, which are routed through the management module.
35501da177e4SLinus Torvalds  */
35511da177e4SLinus Torvalds static int
megaraid_mbox_mm_command(adapter_t * adapter,uioc_t * kioc)35521da177e4SLinus Torvalds megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc)
35531da177e4SLinus Torvalds {
35541da177e4SLinus Torvalds 	struct list_head	*head = &adapter->uscb_pool;
35551da177e4SLinus Torvalds 	mbox64_t		*mbox64;
35561da177e4SLinus Torvalds 	uint8_t			*raw_mbox;
35571da177e4SLinus Torvalds 	scb_t			*scb;
35581da177e4SLinus Torvalds 	mbox_ccb_t		*ccb;
35591da177e4SLinus Torvalds 	unsigned long		flags;
35601da177e4SLinus Torvalds 
35611da177e4SLinus Torvalds 	// detach one scb from free pool
35621da177e4SLinus Torvalds 	spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
35631da177e4SLinus Torvalds 
35641da177e4SLinus Torvalds 	if (list_empty(head)) {	// should never happen because of CMM
35651da177e4SLinus Torvalds 
35661da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
35671da177e4SLinus Torvalds 			"megaraid mbox: bug in cmm handler, lost resources\n"));
35681da177e4SLinus Torvalds 
35691da177e4SLinus Torvalds 		spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
35701da177e4SLinus Torvalds 
35711da177e4SLinus Torvalds 		return (-EINVAL);
35721da177e4SLinus Torvalds 	}
35731da177e4SLinus Torvalds 
35741da177e4SLinus Torvalds 	scb = list_entry(head->next, scb_t, list);
35751da177e4SLinus Torvalds 	list_del_init(&scb->list);
35761da177e4SLinus Torvalds 
35771da177e4SLinus Torvalds 	spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
35781da177e4SLinus Torvalds 
35791da177e4SLinus Torvalds 	scb->state		= SCB_ACTIVE;
35801da177e4SLinus Torvalds 	scb->dma_type		= MRAID_DMA_NONE;
358166e3a241SChristoph Hellwig 	scb->dma_direction	= DMA_NONE;
35821da177e4SLinus Torvalds 
35831da177e4SLinus Torvalds 	ccb		= (mbox_ccb_t *)scb->ccb;
35841da177e4SLinus Torvalds 	mbox64		= (mbox64_t *)(unsigned long)kioc->cmdbuf;
35851da177e4SLinus Torvalds 	raw_mbox	= (uint8_t *)&mbox64->mbox32;
35861da177e4SLinus Torvalds 
35871da177e4SLinus Torvalds 	memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t));
35881da177e4SLinus Torvalds 
35891da177e4SLinus Torvalds 	scb->gp		= (unsigned long)kioc;
35901da177e4SLinus Torvalds 
35911da177e4SLinus Torvalds 	/*
35921da177e4SLinus Torvalds 	 * If it is a logdrv random delete operation, we have to wait till
35931da177e4SLinus Torvalds 	 * there are no outstanding cmds at the fw and then issue it directly
35941da177e4SLinus Torvalds 	 */
35951da177e4SLinus Torvalds 	if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
35961da177e4SLinus Torvalds 
35971da177e4SLinus Torvalds 		if (wait_till_fw_empty(adapter)) {
35981da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
35991da177e4SLinus Torvalds 				"megaraid mbox: LD delete, timed out\n"));
36001da177e4SLinus Torvalds 
36011da177e4SLinus Torvalds 			kioc->status = -ETIME;
36021da177e4SLinus Torvalds 
36031da177e4SLinus Torvalds 			scb->status = -1;
36041da177e4SLinus Torvalds 
36051da177e4SLinus Torvalds 			megaraid_mbox_mm_done(adapter, scb);
36061da177e4SLinus Torvalds 
36071da177e4SLinus Torvalds 			return (-ETIME);
36081da177e4SLinus Torvalds 		}
36091da177e4SLinus Torvalds 
36101da177e4SLinus Torvalds 		INIT_LIST_HEAD(&scb->list);
36111da177e4SLinus Torvalds 
36121da177e4SLinus Torvalds 		scb->state = SCB_ISSUED;
36131da177e4SLinus Torvalds 		if (mbox_post_cmd(adapter, scb) != 0) {
36141da177e4SLinus Torvalds 
36151da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
36161da177e4SLinus Torvalds 				"megaraid mbox: LD delete, mailbox busy\n"));
36171da177e4SLinus Torvalds 
36181da177e4SLinus Torvalds 			kioc->status = -EBUSY;
36191da177e4SLinus Torvalds 
36201da177e4SLinus Torvalds 			scb->status = -1;
36211da177e4SLinus Torvalds 
36221da177e4SLinus Torvalds 			megaraid_mbox_mm_done(adapter, scb);
36231da177e4SLinus Torvalds 
36241da177e4SLinus Torvalds 			return (-EBUSY);
36251da177e4SLinus Torvalds 		}
36261da177e4SLinus Torvalds 
36271da177e4SLinus Torvalds 		return 0;
36281da177e4SLinus Torvalds 	}
36291da177e4SLinus Torvalds 
36301da177e4SLinus Torvalds 	// put the command on the pending list and execute
36311da177e4SLinus Torvalds 	megaraid_mbox_runpendq(adapter, scb);
36321da177e4SLinus Torvalds 
36331da177e4SLinus Torvalds 	return 0;
36341da177e4SLinus Torvalds }
36351da177e4SLinus Torvalds 
36361da177e4SLinus Torvalds 
36371da177e4SLinus Torvalds static int
wait_till_fw_empty(adapter_t * adapter)36381da177e4SLinus Torvalds wait_till_fw_empty(adapter_t *adapter)
36391da177e4SLinus Torvalds {
36401da177e4SLinus Torvalds 	unsigned long	flags = 0;
36411da177e4SLinus Torvalds 	int		i;
36421da177e4SLinus Torvalds 
36431da177e4SLinus Torvalds 
36441da177e4SLinus Torvalds 	/*
36451da177e4SLinus Torvalds 	 * Set the quiescent flag to stop issuing cmds to FW.
36461da177e4SLinus Torvalds 	 */
3647f2c8dc40SChristoph Hellwig 	spin_lock_irqsave(&adapter->lock, flags);
36481da177e4SLinus Torvalds 	adapter->quiescent++;
3649f2c8dc40SChristoph Hellwig 	spin_unlock_irqrestore(&adapter->lock, flags);
36501da177e4SLinus Torvalds 
36511da177e4SLinus Torvalds 	/*
36521da177e4SLinus Torvalds 	 * Wait till there are no more cmds outstanding at FW. Try for at most
36531da177e4SLinus Torvalds 	 * 60 seconds
36541da177e4SLinus Torvalds 	 */
36551da177e4SLinus Torvalds 	for (i = 0; i < 60 && adapter->outstanding_cmds; i++) {
36561da177e4SLinus Torvalds 		con_log(CL_DLEVEL1, (KERN_INFO
36571da177e4SLinus Torvalds 			"megaraid: FW has %d pending commands\n",
36581da177e4SLinus Torvalds 			adapter->outstanding_cmds));
36591da177e4SLinus Torvalds 
36601da177e4SLinus Torvalds 		msleep(1000);
36611da177e4SLinus Torvalds 	}
36621da177e4SLinus Torvalds 
36631da177e4SLinus Torvalds 	return adapter->outstanding_cmds;
36641da177e4SLinus Torvalds }
36651da177e4SLinus Torvalds 
36661da177e4SLinus Torvalds 
36671da177e4SLinus Torvalds /**
36681da177e4SLinus Torvalds  * megaraid_mbox_mm_done - callback for CMM commands
36691da177e4SLinus Torvalds  * @adapter	: HBA soft state
36701da177e4SLinus Torvalds  * @scb		: completed command
36711da177e4SLinus Torvalds  *
36721da177e4SLinus Torvalds  * Callback routine for internal commands originated from the management
36731da177e4SLinus Torvalds  * module.
36741da177e4SLinus Torvalds  */
36751da177e4SLinus Torvalds static void
megaraid_mbox_mm_done(adapter_t * adapter,scb_t * scb)36761da177e4SLinus Torvalds megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
36771da177e4SLinus Torvalds {
36781da177e4SLinus Torvalds 	uioc_t			*kioc;
36791da177e4SLinus Torvalds 	mbox64_t		*mbox64;
36801da177e4SLinus Torvalds 	uint8_t			*raw_mbox;
36811da177e4SLinus Torvalds 	unsigned long		flags;
36821da177e4SLinus Torvalds 
36831da177e4SLinus Torvalds 	kioc			= (uioc_t *)scb->gp;
36841da177e4SLinus Torvalds 	mbox64			= (mbox64_t *)(unsigned long)kioc->cmdbuf;
36851da177e4SLinus Torvalds 	mbox64->mbox32.status	= scb->status;
36861da177e4SLinus Torvalds 	raw_mbox		= (uint8_t *)&mbox64->mbox32;
36871da177e4SLinus Torvalds 
36881da177e4SLinus Torvalds 
36891da177e4SLinus Torvalds 	// put scb in the free pool
36901da177e4SLinus Torvalds 	scb->state	= SCB_FREE;
36911da177e4SLinus Torvalds 	scb->scp	= NULL;
36921da177e4SLinus Torvalds 
36931da177e4SLinus Torvalds 	spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
36941da177e4SLinus Torvalds 
36951da177e4SLinus Torvalds 	list_add(&scb->list, &adapter->uscb_pool);
36961da177e4SLinus Torvalds 
36971da177e4SLinus Torvalds 	spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
36981da177e4SLinus Torvalds 
36991da177e4SLinus Torvalds 	// if a delete logical drive operation succeeded, restart the
37001da177e4SLinus Torvalds 	// controller
37011da177e4SLinus Torvalds 	if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
37021da177e4SLinus Torvalds 
37031da177e4SLinus Torvalds 		adapter->quiescent--;
37041da177e4SLinus Torvalds 
37051da177e4SLinus Torvalds 		megaraid_mbox_runpendq(adapter, NULL);
37061da177e4SLinus Torvalds 	}
37071da177e4SLinus Torvalds 
37081da177e4SLinus Torvalds 	kioc->done(kioc);
37091da177e4SLinus Torvalds 
37101da177e4SLinus Torvalds 	return;
37111da177e4SLinus Torvalds }
37121da177e4SLinus Torvalds 
37131da177e4SLinus Torvalds 
37141da177e4SLinus Torvalds /**
37151da177e4SLinus Torvalds  * gather_hbainfo - HBA characteristics for the applications
3716a69b74d3SRandy Dunlap  * @adapter		: HBA soft state
3717a69b74d3SRandy Dunlap  * @hinfo		: pointer to the caller's host info strucuture
37181da177e4SLinus Torvalds  */
37191da177e4SLinus Torvalds static int
gather_hbainfo(adapter_t * adapter,mraid_hba_info_t * hinfo)37201da177e4SLinus Torvalds gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
37211da177e4SLinus Torvalds {
37221da177e4SLinus Torvalds 	hinfo->pci_vendor_id	= adapter->pdev->vendor;
37231da177e4SLinus Torvalds 	hinfo->pci_device_id	= adapter->pdev->device;
37241da177e4SLinus Torvalds 	hinfo->subsys_vendor_id	= adapter->pdev->subsystem_vendor;
37251da177e4SLinus Torvalds 	hinfo->subsys_device_id	= adapter->pdev->subsystem_device;
37261da177e4SLinus Torvalds 
37271da177e4SLinus Torvalds 	hinfo->pci_bus		= adapter->pdev->bus->number;
37281da177e4SLinus Torvalds 	hinfo->pci_dev_fn	= adapter->pdev->devfn;
37291da177e4SLinus Torvalds 	hinfo->pci_slot		= PCI_SLOT(adapter->pdev->devfn);
37301da177e4SLinus Torvalds 	hinfo->irq		= adapter->host->irq;
37311da177e4SLinus Torvalds 	hinfo->baseport		= ADAP2RAIDDEV(adapter)->baseport;
37321da177e4SLinus Torvalds 
37331da177e4SLinus Torvalds 	hinfo->unique_id	= (hinfo->pci_bus << 8) | adapter->pdev->devfn;
37341da177e4SLinus Torvalds 	hinfo->host_no		= adapter->host->host_no;
37351da177e4SLinus Torvalds 
37361da177e4SLinus Torvalds 	return 0;
37371da177e4SLinus Torvalds }
37381da177e4SLinus Torvalds 
37391da177e4SLinus Torvalds /*
37401da177e4SLinus Torvalds  * END: Interface for the common management module
37411da177e4SLinus Torvalds  */
37421da177e4SLinus Torvalds 
37431da177e4SLinus Torvalds 
37441da177e4SLinus Torvalds 
37451da177e4SLinus Torvalds /**
37461da177e4SLinus Torvalds  * megaraid_sysfs_alloc_resources - allocate sysfs related resources
3747a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
37481da177e4SLinus Torvalds  *
37491da177e4SLinus Torvalds  * Allocate packets required to issue FW calls whenever the sysfs attributes
37501da177e4SLinus Torvalds  * are read. These attributes would require up-to-date information from the
37511da177e4SLinus Torvalds  * FW. Also set up resources for mutual exclusion to share these resources and
37521da177e4SLinus Torvalds  * the wait queue.
37531da177e4SLinus Torvalds  *
3754a69b74d3SRandy Dunlap  * Return 0 on success.
3755a69b74d3SRandy Dunlap  * Return -ERROR_CODE on failure.
37561da177e4SLinus Torvalds  */
37571da177e4SLinus Torvalds static int
megaraid_sysfs_alloc_resources(adapter_t * adapter)37581da177e4SLinus Torvalds megaraid_sysfs_alloc_resources(adapter_t *adapter)
37591da177e4SLinus Torvalds {
37601da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
37611da177e4SLinus Torvalds 	int		rval = 0;
37621da177e4SLinus Torvalds 
37631da177e4SLinus Torvalds 	raid_dev->sysfs_uioc = kmalloc(sizeof(uioc_t), GFP_KERNEL);
37641da177e4SLinus Torvalds 
37651da177e4SLinus Torvalds 	raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL);
37661da177e4SLinus Torvalds 
376766e3a241SChristoph Hellwig 	raid_dev->sysfs_buffer = dma_alloc_coherent(&adapter->pdev->dev,
376866e3a241SChristoph Hellwig 			PAGE_SIZE, &raid_dev->sysfs_buffer_dma, GFP_KERNEL);
37691da177e4SLinus Torvalds 
37701da177e4SLinus Torvalds 	if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 ||
37711da177e4SLinus Torvalds 		!raid_dev->sysfs_buffer) {
37721da177e4SLinus Torvalds 
37731da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_WARNING
3774cadbd4a5SHarvey Harrison 			"megaraid: out of memory, %s %d\n", __func__,
37751da177e4SLinus Torvalds 			__LINE__));
37761da177e4SLinus Torvalds 
37771da177e4SLinus Torvalds 		rval = -ENOMEM;
37781da177e4SLinus Torvalds 
37791da177e4SLinus Torvalds 		megaraid_sysfs_free_resources(adapter);
37801da177e4SLinus Torvalds 	}
37811da177e4SLinus Torvalds 
37820c2cc433SMatthias Kaehlcke 	mutex_init(&raid_dev->sysfs_mtx);
37831da177e4SLinus Torvalds 
37841da177e4SLinus Torvalds 	init_waitqueue_head(&raid_dev->sysfs_wait_q);
37851da177e4SLinus Torvalds 
37861da177e4SLinus Torvalds 	return rval;
37871da177e4SLinus Torvalds }
37881da177e4SLinus Torvalds 
37891da177e4SLinus Torvalds 
37901da177e4SLinus Torvalds /**
37911da177e4SLinus Torvalds  * megaraid_sysfs_free_resources - free sysfs related resources
3792a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
37931da177e4SLinus Torvalds  *
37941da177e4SLinus Torvalds  * Free packets allocated for sysfs FW commands
37951da177e4SLinus Torvalds  */
37961da177e4SLinus Torvalds static void
megaraid_sysfs_free_resources(adapter_t * adapter)37971da177e4SLinus Torvalds megaraid_sysfs_free_resources(adapter_t *adapter)
37981da177e4SLinus Torvalds {
37991da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
38001da177e4SLinus Torvalds 
3801c9475cb0SJesper Juhl 	kfree(raid_dev->sysfs_uioc);
3802c9475cb0SJesper Juhl 	kfree(raid_dev->sysfs_mbox64);
38031da177e4SLinus Torvalds 
38041da177e4SLinus Torvalds 	if (raid_dev->sysfs_buffer) {
380566e3a241SChristoph Hellwig 		dma_free_coherent(&adapter->pdev->dev, PAGE_SIZE,
38061da177e4SLinus Torvalds 			raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma);
38071da177e4SLinus Torvalds 	}
38081da177e4SLinus Torvalds }
38091da177e4SLinus Torvalds 
38101da177e4SLinus Torvalds 
38111da177e4SLinus Torvalds /**
38121da177e4SLinus Torvalds  * megaraid_sysfs_get_ldmap_done - callback for get ldmap
3813a69b74d3SRandy Dunlap  * @uioc	: completed packet
38141da177e4SLinus Torvalds  *
38151da177e4SLinus Torvalds  * Callback routine called in the ISR/tasklet context for get ldmap call
38161da177e4SLinus Torvalds  */
38171da177e4SLinus Torvalds static void
megaraid_sysfs_get_ldmap_done(uioc_t * uioc)38181da177e4SLinus Torvalds megaraid_sysfs_get_ldmap_done(uioc_t *uioc)
38191da177e4SLinus Torvalds {
38201da177e4SLinus Torvalds 	adapter_t	*adapter = (adapter_t *)uioc->buf_vaddr;
38211da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
38221da177e4SLinus Torvalds 
38231da177e4SLinus Torvalds 	uioc->status = 0;
38241da177e4SLinus Torvalds 
38251da177e4SLinus Torvalds 	wake_up(&raid_dev->sysfs_wait_q);
38261da177e4SLinus Torvalds }
38271da177e4SLinus Torvalds 
38281da177e4SLinus Torvalds /**
38291da177e4SLinus Torvalds  * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap
3830c251a7beSKees Cook  * @t	: timed out timer
38311da177e4SLinus Torvalds  *
38321da177e4SLinus Torvalds  * Timeout routine to recover and return to application, in case the adapter
3833a69b74d3SRandy Dunlap  * has stopped responding. A timeout of 60 seconds for this command seems like
3834a69b74d3SRandy Dunlap  * a good value.
38351da177e4SLinus Torvalds  */
38361da177e4SLinus Torvalds static void
megaraid_sysfs_get_ldmap_timeout(struct timer_list * t)3837c251a7beSKees Cook megaraid_sysfs_get_ldmap_timeout(struct timer_list *t)
38381da177e4SLinus Torvalds {
3839c251a7beSKees Cook 	struct uioc_timeout *timeout = from_timer(timeout, t, timer);
3840c251a7beSKees Cook 	uioc_t		*uioc = timeout->uioc;
38411da177e4SLinus Torvalds 	adapter_t	*adapter = (adapter_t *)uioc->buf_vaddr;
38421da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
38431da177e4SLinus Torvalds 
38441da177e4SLinus Torvalds 	uioc->status = -ETIME;
38451da177e4SLinus Torvalds 
38461da177e4SLinus Torvalds 	wake_up(&raid_dev->sysfs_wait_q);
38471da177e4SLinus Torvalds }
38481da177e4SLinus Torvalds 
38491da177e4SLinus Torvalds 
38501da177e4SLinus Torvalds /**
38511da177e4SLinus Torvalds  * megaraid_sysfs_get_ldmap - get update logical drive map
3852a69b74d3SRandy Dunlap  * @adapter	: controller's soft state
38531da177e4SLinus Torvalds  *
38541da177e4SLinus Torvalds  * This routine will be called whenever user reads the logical drive
38551da177e4SLinus Torvalds  * attributes, go get the current logical drive mapping table from the
3856b1c11812SJoe Perches  * firmware. We use the management API's to issue commands to the controller.
38571da177e4SLinus Torvalds  *
38581da177e4SLinus Torvalds  * NOTE: The commands issuance functionality is not generalized and
38591da177e4SLinus Torvalds  * implemented in context of "get ld map" command only. If required, the
38601da177e4SLinus Torvalds  * command issuance logical can be trivially pulled out and implemented as a
386125985edcSLucas De Marchi  * standalone library. For now, this should suffice since there is no other
38621da177e4SLinus Torvalds  * user of this interface.
38631da177e4SLinus Torvalds  *
3864a69b74d3SRandy Dunlap  * Return 0 on success.
3865a69b74d3SRandy Dunlap  * Return -1 on failure.
38661da177e4SLinus Torvalds  */
38671da177e4SLinus Torvalds static int
megaraid_sysfs_get_ldmap(adapter_t * adapter)38681da177e4SLinus Torvalds megaraid_sysfs_get_ldmap(adapter_t *adapter)
38691da177e4SLinus Torvalds {
38701da177e4SLinus Torvalds 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
38711da177e4SLinus Torvalds 	uioc_t			*uioc;
38721da177e4SLinus Torvalds 	mbox64_t		*mbox64;
38731da177e4SLinus Torvalds 	mbox_t			*mbox;
38741da177e4SLinus Torvalds 	char			*raw_mbox;
3875c251a7beSKees Cook 	struct uioc_timeout	timeout;
38761da177e4SLinus Torvalds 	caddr_t			ldmap;
38771da177e4SLinus Torvalds 	int			rval = 0;
38781da177e4SLinus Torvalds 
38791da177e4SLinus Torvalds 	/*
38801da177e4SLinus Torvalds 	 * Allow only one read at a time to go through the sysfs attributes
38811da177e4SLinus Torvalds 	 */
38820c2cc433SMatthias Kaehlcke 	mutex_lock(&raid_dev->sysfs_mtx);
38831da177e4SLinus Torvalds 
38841da177e4SLinus Torvalds 	uioc	= raid_dev->sysfs_uioc;
38851da177e4SLinus Torvalds 	mbox64	= raid_dev->sysfs_mbox64;
38861da177e4SLinus Torvalds 	ldmap	= raid_dev->sysfs_buffer;
38871da177e4SLinus Torvalds 
38881da177e4SLinus Torvalds 	memset(uioc, 0, sizeof(uioc_t));
38891da177e4SLinus Torvalds 	memset(mbox64, 0, sizeof(mbox64_t));
38901da177e4SLinus Torvalds 	memset(ldmap, 0, sizeof(raid_dev->curr_ldmap));
38911da177e4SLinus Torvalds 
38921da177e4SLinus Torvalds 	mbox		= &mbox64->mbox32;
38931da177e4SLinus Torvalds 	raw_mbox	= (char *)mbox;
38941da177e4SLinus Torvalds 	uioc->cmdbuf    = (uint64_t)(unsigned long)mbox64;
38951da177e4SLinus Torvalds 	uioc->buf_vaddr	= (caddr_t)adapter;
38961da177e4SLinus Torvalds 	uioc->status	= -ENODATA;
38971da177e4SLinus Torvalds 	uioc->done	= megaraid_sysfs_get_ldmap_done;
38981da177e4SLinus Torvalds 
38991da177e4SLinus Torvalds 	/*
39001da177e4SLinus Torvalds 	 * Prepare the mailbox packet to get the current logical drive mapping
39011da177e4SLinus Torvalds 	 * table
39021da177e4SLinus Torvalds 	 */
39031da177e4SLinus Torvalds 	mbox->xferaddr = (uint32_t)raid_dev->sysfs_buffer_dma;
39041da177e4SLinus Torvalds 
39051da177e4SLinus Torvalds 	raw_mbox[0] = FC_DEL_LOGDRV;
39061da177e4SLinus Torvalds 	raw_mbox[2] = OP_GET_LDID_MAP;
39071da177e4SLinus Torvalds 
39081da177e4SLinus Torvalds 	/*
39091da177e4SLinus Torvalds 	 * Setup a timer to recover from a non-responding controller
39101da177e4SLinus Torvalds 	 */
3911c251a7beSKees Cook 	timeout.uioc = uioc;
3912c251a7beSKees Cook 	timer_setup_on_stack(&timeout.timer,
3913c251a7beSKees Cook 			     megaraid_sysfs_get_ldmap_timeout, 0);
39141da177e4SLinus Torvalds 
3915c251a7beSKees Cook 	timeout.timer.expires		= jiffies + 60 * HZ;
3916c251a7beSKees Cook 	add_timer(&timeout.timer);
39171da177e4SLinus Torvalds 
39181da177e4SLinus Torvalds 	/*
39191da177e4SLinus Torvalds 	 * Send the command to the firmware
39201da177e4SLinus Torvalds 	 */
39211da177e4SLinus Torvalds 	rval = megaraid_mbox_mm_command(adapter, uioc);
39221da177e4SLinus Torvalds 
39231da177e4SLinus Torvalds 	if (rval == 0) {	// command successfully issued
39241da177e4SLinus Torvalds 		wait_event(raid_dev->sysfs_wait_q, (uioc->status != -ENODATA));
39251da177e4SLinus Torvalds 
39261da177e4SLinus Torvalds 		/*
39271da177e4SLinus Torvalds 		 * Check if the command timed out
39281da177e4SLinus Torvalds 		 */
39291da177e4SLinus Torvalds 		if (uioc->status == -ETIME) {
39301da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
39311da177e4SLinus Torvalds 				"megaraid: sysfs get ld map timed out\n"));
39321da177e4SLinus Torvalds 
39331da177e4SLinus Torvalds 			rval = -ETIME;
39341da177e4SLinus Torvalds 		}
39351da177e4SLinus Torvalds 		else {
39361da177e4SLinus Torvalds 			rval = mbox->status;
39371da177e4SLinus Torvalds 		}
39381da177e4SLinus Torvalds 
39391da177e4SLinus Torvalds 		if (rval == 0) {
39401da177e4SLinus Torvalds 			memcpy(raid_dev->curr_ldmap, ldmap,
39411da177e4SLinus Torvalds 				sizeof(raid_dev->curr_ldmap));
39421da177e4SLinus Torvalds 		}
39431da177e4SLinus Torvalds 		else {
39441da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
39451da177e4SLinus Torvalds 				"megaraid: get ld map failed with %x\n", rval));
39461da177e4SLinus Torvalds 		}
39471da177e4SLinus Torvalds 	}
39481da177e4SLinus Torvalds 	else {
39491da177e4SLinus Torvalds 		con_log(CL_ANN, (KERN_NOTICE
39501da177e4SLinus Torvalds 			"megaraid: could not issue ldmap command:%x\n", rval));
39511da177e4SLinus Torvalds 	}
39521da177e4SLinus Torvalds 
39531da177e4SLinus Torvalds 
3954c251a7beSKees Cook 	del_timer_sync(&timeout.timer);
3955c251a7beSKees Cook 	destroy_timer_on_stack(&timeout.timer);
39561da177e4SLinus Torvalds 
39570c2cc433SMatthias Kaehlcke 	mutex_unlock(&raid_dev->sysfs_mtx);
39581da177e4SLinus Torvalds 
39591da177e4SLinus Torvalds 	return rval;
39601da177e4SLinus Torvalds }
39611da177e4SLinus Torvalds 
39621da177e4SLinus Torvalds 
39631da177e4SLinus Torvalds /**
39644c92f898SZhen Lei  * megaraid_mbox_app_hndl_show - display application handle for this adapter
39652b46e5c1SDamien Le Moal  * @dev		: class device object representation for the host
39662b46e5c1SDamien Le Moal  * @attr	: device attribute (unused)
3967a69b74d3SRandy Dunlap  * @buf		: buffer to send data to
39681da177e4SLinus Torvalds  *
39691da177e4SLinus Torvalds  * Display the handle used by the applications while executing management
39701da177e4SLinus Torvalds  * tasks on the adapter. We invoke a management module API to get the adapter
39711da177e4SLinus Torvalds  * handle, since we do not interface with applications directly.
39721da177e4SLinus Torvalds  */
39731da177e4SLinus Torvalds static ssize_t
megaraid_mbox_app_hndl_show(struct device * dev,struct device_attribute * attr,char * buf)39744c92f898SZhen Lei megaraid_mbox_app_hndl_show(struct device *dev, struct device_attribute *attr, char *buf)
39751da177e4SLinus Torvalds {
3976ee959b00STony Jones 	struct Scsi_Host *shost = class_to_shost(dev);
39771da177e4SLinus Torvalds 	adapter_t	*adapter = (adapter_t *)SCSIHOST2ADAP(shost);
39781da177e4SLinus Torvalds 	uint32_t	app_hndl;
39791da177e4SLinus Torvalds 
39801da177e4SLinus Torvalds 	app_hndl = mraid_mm_adapter_app_handle(adapter->unique_id);
39811da177e4SLinus Torvalds 
398268a97febSXuezhi Zhang 	return sysfs_emit(buf, "%u\n", app_hndl);
39831da177e4SLinus Torvalds }
39841da177e4SLinus Torvalds 
39851da177e4SLinus Torvalds 
39861da177e4SLinus Torvalds /**
39874c92f898SZhen Lei  * megaraid_mbox_ld_show - display the logical drive number for this device
3988a69b74d3SRandy Dunlap  * @dev		: device object representation for the scsi device
3989a69b74d3SRandy Dunlap  * @attr	: device attribute to show
3990a69b74d3SRandy Dunlap  * @buf		: buffer to send data to
39911da177e4SLinus Torvalds  *
39921da177e4SLinus Torvalds  * Display the logical drive number for the device in question, if it a valid
3993a69b74d3SRandy Dunlap  * logical drive. For physical devices, "-1" is returned.
3994a69b74d3SRandy Dunlap  *
3995a69b74d3SRandy Dunlap  * The logical drive number is displayed in following format:
39961da177e4SLinus Torvalds  *
39971da177e4SLinus Torvalds  * <SCSI ID> <LD NUM> <LD STICKY ID> <APP ADAPTER HANDLE>
39981da177e4SLinus Torvalds  *
3999a69b74d3SRandy Dunlap  *   <int>     <int>       <int>            <int>
40001da177e4SLinus Torvalds  */
40011da177e4SLinus Torvalds static ssize_t
megaraid_mbox_ld_show(struct device * dev,struct device_attribute * attr,char * buf)40024c92f898SZhen Lei megaraid_mbox_ld_show(struct device *dev, struct device_attribute *attr, char *buf)
40031da177e4SLinus Torvalds {
40041da177e4SLinus Torvalds 	struct scsi_device *sdev = to_scsi_device(dev);
40051da177e4SLinus Torvalds 	adapter_t	*adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host);
40061da177e4SLinus Torvalds 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
40071da177e4SLinus Torvalds 	int		scsi_id = -1;
40081da177e4SLinus Torvalds 	int		logical_drv = -1;
40091da177e4SLinus Torvalds 	int		ldid_map = -1;
40101da177e4SLinus Torvalds 	uint32_t	app_hndl = 0;
40111da177e4SLinus Torvalds 	int		mapped_sdev_id;
40121da177e4SLinus Torvalds 	int		rval;
40131da177e4SLinus Torvalds 	int		i;
40141da177e4SLinus Torvalds 
40151da177e4SLinus Torvalds 	if (raid_dev->random_del_supported &&
40161da177e4SLinus Torvalds 			MRAID_IS_LOGICAL_SDEV(adapter, sdev)) {
40171da177e4SLinus Torvalds 
40181da177e4SLinus Torvalds 		rval = megaraid_sysfs_get_ldmap(adapter);
40191da177e4SLinus Torvalds 		if (rval == 0) {
40201da177e4SLinus Torvalds 
40211da177e4SLinus Torvalds 			for (i = 0; i < MAX_LOGICAL_DRIVES_40LD; i++) {
40221da177e4SLinus Torvalds 
40231da177e4SLinus Torvalds 				mapped_sdev_id = sdev->id;
40241da177e4SLinus Torvalds 
40251da177e4SLinus Torvalds 				if (sdev->id > adapter->init_id) {
40261da177e4SLinus Torvalds 					mapped_sdev_id -= 1;
40271da177e4SLinus Torvalds 				}
40281da177e4SLinus Torvalds 
40291da177e4SLinus Torvalds 				if (raid_dev->curr_ldmap[i] == mapped_sdev_id) {
40301da177e4SLinus Torvalds 
40311da177e4SLinus Torvalds 					scsi_id = sdev->id;
40321da177e4SLinus Torvalds 
40331da177e4SLinus Torvalds 					logical_drv = i;
40341da177e4SLinus Torvalds 
40351da177e4SLinus Torvalds 					ldid_map = raid_dev->curr_ldmap[i];
40361da177e4SLinus Torvalds 
40371da177e4SLinus Torvalds 					app_hndl = mraid_mm_adapter_app_handle(
40381da177e4SLinus Torvalds 							adapter->unique_id);
40391da177e4SLinus Torvalds 
40401da177e4SLinus Torvalds 					break;
40411da177e4SLinus Torvalds 				}
40421da177e4SLinus Torvalds 			}
40431da177e4SLinus Torvalds 		}
40441da177e4SLinus Torvalds 		else {
40451da177e4SLinus Torvalds 			con_log(CL_ANN, (KERN_NOTICE
40461da177e4SLinus Torvalds 				"megaraid: sysfs get ld map failed: %x\n",
40471da177e4SLinus Torvalds 				rval));
40481da177e4SLinus Torvalds 		}
40491da177e4SLinus Torvalds 	}
40501da177e4SLinus Torvalds 
405168a97febSXuezhi Zhang 	return sysfs_emit(buf, "%d %d %d %d\n", scsi_id, logical_drv,
40521da177e4SLinus Torvalds 			ldid_map, app_hndl);
40531da177e4SLinus Torvalds }
40541da177e4SLinus Torvalds 
40551da177e4SLinus Torvalds 
40561da177e4SLinus Torvalds /*
40571da177e4SLinus Torvalds  * END: Mailbox Low Level Driver
40581da177e4SLinus Torvalds  */
40591da177e4SLinus Torvalds module_init(megaraid_init);
40601da177e4SLinus Torvalds module_exit(megaraid_exit);
4061