xref: /openbmc/linux/drivers/scsi/aacraid/aachba.c (revision 3ffd6c5a)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	Adaptec AAC series RAID controller driver
3fa195afeSAlan Cox  *	(c) Copyright 2001 Red Hat Inc.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * based on the old aacraid driver that is..
61da177e4SLinus Torvalds  * Adaptec aacraid device driver for Linux.
71da177e4SLinus Torvalds  *
8e8b12f0fSMahesh Rajashekhara  * Copyright (c) 2000-2010 Adaptec, Inc.
9e8b12f0fSMahesh Rajashekhara  *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
121da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
131da177e4SLinus Torvalds  * the Free Software Foundation; either version 2, or (at your option)
141da177e4SLinus Torvalds  * any later version.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
171da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
181da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
191da177e4SLinus Torvalds  * GNU General Public License for more details.
201da177e4SLinus Torvalds  *
211da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
221da177e4SLinus Torvalds  * along with this program; see the file COPYING.  If not, write to
231da177e4SLinus Torvalds  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include <linux/kernel.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/pci.h>
311da177e4SLinus Torvalds #include <linux/spinlock.h>
321da177e4SLinus Torvalds #include <linux/slab.h>
331da177e4SLinus Torvalds #include <linux/completion.h>
341da177e4SLinus Torvalds #include <linux/blkdev.h>
357c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
363a0086a8SSalyzyn, Mark #include <linux/highmem.h> /* For flush_kernel_dcache_page */
37acf3368fSPaul Gortmaker #include <linux/module.h>
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #include <scsi/scsi.h>
401da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
411da177e4SLinus Torvalds #include <scsi/scsi_device.h>
421da177e4SLinus Torvalds #include <scsi/scsi_host.h>
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds #include "aacraid.h"
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds /* values for inqd_pdt: Peripheral device type in plain English */
471da177e4SLinus Torvalds #define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
481da177e4SLinus Torvalds #define	INQD_PDT_PROC	0x03	/* Processor device */
491da177e4SLinus Torvalds #define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
501da177e4SLinus Torvalds #define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
511da177e4SLinus Torvalds #define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
521da177e4SLinus Torvalds #define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
551da177e4SLinus Torvalds #define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds /*
581da177e4SLinus Torvalds  *	Sense codes
591da177e4SLinus Torvalds  */
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds #define SENCODE_NO_SENSE			0x00
621da177e4SLinus Torvalds #define SENCODE_END_OF_DATA			0x00
631da177e4SLinus Torvalds #define SENCODE_BECOMING_READY			0x04
641da177e4SLinus Torvalds #define SENCODE_INIT_CMD_REQUIRED		0x04
651da177e4SLinus Torvalds #define SENCODE_PARAM_LIST_LENGTH_ERROR		0x1A
661da177e4SLinus Torvalds #define SENCODE_INVALID_COMMAND			0x20
671da177e4SLinus Torvalds #define SENCODE_LBA_OUT_OF_RANGE		0x21
681da177e4SLinus Torvalds #define SENCODE_INVALID_CDB_FIELD		0x24
691da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SUPPORTED		0x25
701da177e4SLinus Torvalds #define SENCODE_INVALID_PARAM_FIELD		0x26
711da177e4SLinus Torvalds #define SENCODE_PARAM_NOT_SUPPORTED		0x26
721da177e4SLinus Torvalds #define SENCODE_PARAM_VALUE_INVALID		0x26
731da177e4SLinus Torvalds #define SENCODE_RESET_OCCURRED			0x29
741da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x3E
751da177e4SLinus Torvalds #define SENCODE_INQUIRY_DATA_CHANGED		0x3F
761da177e4SLinus Torvalds #define SENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x39
771da177e4SLinus Torvalds #define SENCODE_DIAGNOSTIC_FAILURE		0x40
781da177e4SLinus Torvalds #define SENCODE_INTERNAL_TARGET_FAILURE		0x44
791da177e4SLinus Torvalds #define SENCODE_INVALID_MESSAGE_ERROR		0x49
801da177e4SLinus Torvalds #define SENCODE_LUN_FAILED_SELF_CONFIG		0x4c
811da177e4SLinus Torvalds #define SENCODE_OVERLAPPED_COMMAND		0x4E
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds /*
841da177e4SLinus Torvalds  *	Additional sense codes
851da177e4SLinus Torvalds  */
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds #define ASENCODE_NO_SENSE			0x00
881da177e4SLinus Torvalds #define ASENCODE_END_OF_DATA			0x05
891da177e4SLinus Torvalds #define ASENCODE_BECOMING_READY			0x01
901da177e4SLinus Torvalds #define ASENCODE_INIT_CMD_REQUIRED		0x02
911da177e4SLinus Torvalds #define ASENCODE_PARAM_LIST_LENGTH_ERROR	0x00
921da177e4SLinus Torvalds #define ASENCODE_INVALID_COMMAND		0x00
931da177e4SLinus Torvalds #define ASENCODE_LBA_OUT_OF_RANGE		0x00
941da177e4SLinus Torvalds #define ASENCODE_INVALID_CDB_FIELD		0x00
951da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SUPPORTED		0x00
961da177e4SLinus Torvalds #define ASENCODE_INVALID_PARAM_FIELD		0x00
971da177e4SLinus Torvalds #define ASENCODE_PARAM_NOT_SUPPORTED		0x01
981da177e4SLinus Torvalds #define ASENCODE_PARAM_VALUE_INVALID		0x02
991da177e4SLinus Torvalds #define ASENCODE_RESET_OCCURRED			0x00
1001da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x00
1011da177e4SLinus Torvalds #define ASENCODE_INQUIRY_DATA_CHANGED		0x03
1021da177e4SLinus Torvalds #define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x00
1031da177e4SLinus Torvalds #define ASENCODE_DIAGNOSTIC_FAILURE		0x80
1041da177e4SLinus Torvalds #define ASENCODE_INTERNAL_TARGET_FAILURE	0x00
1051da177e4SLinus Torvalds #define ASENCODE_INVALID_MESSAGE_ERROR		0x00
1061da177e4SLinus Torvalds #define ASENCODE_LUN_FAILED_SELF_CONFIG		0x00
1071da177e4SLinus Torvalds #define ASENCODE_OVERLAPPED_COMMAND		0x00
1081da177e4SLinus Torvalds 
109c4e2fbcaSRaghava Aditya Renukunta #define AAC_STAT_GOOD (DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD)
110c4e2fbcaSRaghava Aditya Renukunta 
1111da177e4SLinus Torvalds #define BYTE0(x) (unsigned char)(x)
1121da177e4SLinus Torvalds #define BYTE1(x) (unsigned char)((x) >> 8)
1131da177e4SLinus Torvalds #define BYTE2(x) (unsigned char)((x) >> 16)
1141da177e4SLinus Torvalds #define BYTE3(x) (unsigned char)((x) >> 24)
1151da177e4SLinus Torvalds 
116b836439fSMahesh Rajashekhara /* MODE_SENSE data format */
117b836439fSMahesh Rajashekhara typedef struct {
118b836439fSMahesh Rajashekhara 	struct {
119b836439fSMahesh Rajashekhara 		u8	data_length;
120b836439fSMahesh Rajashekhara 		u8	med_type;
121b836439fSMahesh Rajashekhara 		u8	dev_par;
122b836439fSMahesh Rajashekhara 		u8	bd_length;
123b836439fSMahesh Rajashekhara 	} __attribute__((packed)) hd;
124b836439fSMahesh Rajashekhara 	struct {
125b836439fSMahesh Rajashekhara 		u8	dens_code;
126b836439fSMahesh Rajashekhara 		u8	block_count[3];
127b836439fSMahesh Rajashekhara 		u8	reserved;
128b836439fSMahesh Rajashekhara 		u8	block_length[3];
129b836439fSMahesh Rajashekhara 	} __attribute__((packed)) bd;
130b836439fSMahesh Rajashekhara 		u8	mpc_buf[3];
131b836439fSMahesh Rajashekhara } __attribute__((packed)) aac_modep_data;
132b836439fSMahesh Rajashekhara 
133b836439fSMahesh Rajashekhara /* MODE_SENSE_10 data format */
134b836439fSMahesh Rajashekhara typedef struct {
135b836439fSMahesh Rajashekhara 	struct {
136b836439fSMahesh Rajashekhara 		u8	data_length[2];
137b836439fSMahesh Rajashekhara 		u8	med_type;
138b836439fSMahesh Rajashekhara 		u8	dev_par;
139b836439fSMahesh Rajashekhara 		u8	rsrvd[2];
140b836439fSMahesh Rajashekhara 		u8	bd_length[2];
141b836439fSMahesh Rajashekhara 	} __attribute__((packed)) hd;
142b836439fSMahesh Rajashekhara 	struct {
143b836439fSMahesh Rajashekhara 		u8	dens_code;
144b836439fSMahesh Rajashekhara 		u8	block_count[3];
145b836439fSMahesh Rajashekhara 		u8	reserved;
146b836439fSMahesh Rajashekhara 		u8	block_length[3];
147b836439fSMahesh Rajashekhara 	} __attribute__((packed)) bd;
148b836439fSMahesh Rajashekhara 		u8	mpc_buf[3];
149b836439fSMahesh Rajashekhara } __attribute__((packed)) aac_modep10_data;
150b836439fSMahesh Rajashekhara 
1511da177e4SLinus Torvalds /*------------------------------------------------------------------------------
1521da177e4SLinus Torvalds  *              S T R U C T S / T Y P E D E F S
1531da177e4SLinus Torvalds  *----------------------------------------------------------------------------*/
1541da177e4SLinus Torvalds /* SCSI inquiry data */
1551da177e4SLinus Torvalds struct inquiry_data {
1561da177e4SLinus Torvalds 	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type */
1571da177e4SLinus Torvalds 	u8 inqd_dtq;	/* RMB | Device Type Qualifier */
1581da177e4SLinus Torvalds 	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
1591da177e4SLinus Torvalds 	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
1601da177e4SLinus Torvalds 	u8 inqd_len;	/* Additional length (n-4) */
1611da177e4SLinus Torvalds 	u8 inqd_pad1[2];/* Reserved - must be zero */
1621da177e4SLinus Torvalds 	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
1631da177e4SLinus Torvalds 	u8 inqd_vid[8];	/* Vendor ID */
1641da177e4SLinus Torvalds 	u8 inqd_pid[16];/* Product ID */
1651da177e4SLinus Torvalds 	u8 inqd_prl[4];	/* Product Revision Level */
1661da177e4SLinus Torvalds };
1671da177e4SLinus Torvalds 
1685d910649SMahesh Rajashekhara /* Added for VPD 0x83 */
1695d910649SMahesh Rajashekhara typedef struct {
1705d910649SMahesh Rajashekhara 	u8 CodeSet:4;	/* VPD_CODE_SET */
1715d910649SMahesh Rajashekhara 	u8 Reserved:4;
1725d910649SMahesh Rajashekhara 	u8 IdentifierType:4;	/* VPD_IDENTIFIER_TYPE */
1735d910649SMahesh Rajashekhara 	u8 Reserved2:4;
1745d910649SMahesh Rajashekhara 	u8 Reserved3;
1755d910649SMahesh Rajashekhara 	u8 IdentifierLength;
1765d910649SMahesh Rajashekhara 	u8 VendId[8];
1775d910649SMahesh Rajashekhara 	u8 ProductId[16];
1785d910649SMahesh Rajashekhara 	u8 SerialNumber[8];	/* SN in ASCII */
1795d910649SMahesh Rajashekhara 
1805d910649SMahesh Rajashekhara } TVPD_ID_Descriptor_Type_1;
1815d910649SMahesh Rajashekhara 
1825d910649SMahesh Rajashekhara typedef struct {
1835d910649SMahesh Rajashekhara 	u8 CodeSet:4;	/* VPD_CODE_SET */
1845d910649SMahesh Rajashekhara 	u8 Reserved:4;
1855d910649SMahesh Rajashekhara 	u8 IdentifierType:4;	/* VPD_IDENTIFIER_TYPE */
1865d910649SMahesh Rajashekhara 	u8 Reserved2:4;
1875d910649SMahesh Rajashekhara 	u8 Reserved3;
1885d910649SMahesh Rajashekhara 	u8 IdentifierLength;
1895d910649SMahesh Rajashekhara 	struct TEU64Id {
1905d910649SMahesh Rajashekhara 		u32 Serial;
1915d910649SMahesh Rajashekhara 		 /* The serial number supposed to be 40 bits,
1925d910649SMahesh Rajashekhara 		  * bit we only support 32, so make the last byte zero. */
1935d910649SMahesh Rajashekhara 		u8 Reserved;
1945d910649SMahesh Rajashekhara 		u8 VendId[3];
1955d910649SMahesh Rajashekhara 	} EU64Id;
1965d910649SMahesh Rajashekhara 
1975d910649SMahesh Rajashekhara } TVPD_ID_Descriptor_Type_2;
1985d910649SMahesh Rajashekhara 
1995d910649SMahesh Rajashekhara typedef struct {
2005d910649SMahesh Rajashekhara 	u8 DeviceType:5;
2015d910649SMahesh Rajashekhara 	u8 DeviceTypeQualifier:3;
2025d910649SMahesh Rajashekhara 	u8 PageCode;
2035d910649SMahesh Rajashekhara 	u8 Reserved;
2045d910649SMahesh Rajashekhara 	u8 PageLength;
2055d910649SMahesh Rajashekhara 	TVPD_ID_Descriptor_Type_1 IdDescriptorType1;
2065d910649SMahesh Rajashekhara 	TVPD_ID_Descriptor_Type_2 IdDescriptorType2;
2075d910649SMahesh Rajashekhara 
2085d910649SMahesh Rajashekhara } TVPD_Page83;
2095d910649SMahesh Rajashekhara 
2101da177e4SLinus Torvalds /*
2111da177e4SLinus Torvalds  *              M O D U L E   G L O B A L S
2121da177e4SLinus Torvalds  */
2131da177e4SLinus Torvalds 
2140b433447SMahesh Rajashekhara static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *sgmap);
2150b433447SMahesh Rajashekhara static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg);
2160b433447SMahesh Rajashekhara static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg);
2170b433447SMahesh Rajashekhara static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
2180b433447SMahesh Rajashekhara 				struct aac_raw_io2 *rio2, int sg_max);
2190b433447SMahesh Rajashekhara static int aac_convert_sgraw2(struct aac_raw_io2 *rio2,
2200b433447SMahesh Rajashekhara 				int pages, int nseg, int nseg_new);
2211da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
2221da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
2231da177e4SLinus Torvalds static char *aac_get_status_string(u32 status);
2241da177e4SLinus Torvalds #endif
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds /*
2271da177e4SLinus Torvalds  *	Non dasd selection is handled entirely in aachba now
2281da177e4SLinus Torvalds  */
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds static int nondasd = -1;
231d8e96507SLeubner, Achim static int aac_cache = 2;	/* WCE=0 to avoid performance problems */
2321da177e4SLinus Torvalds static int dacmode = -1;
2338ef22247SSalyzyn, Mark int aac_msi;
2341208bab5SSalyzyn, Mark int aac_commit = -1;
235404d9a90SMark Haverkamp int startup_timeout = 180;
236404d9a90SMark Haverkamp int aif_timeout = 120;
23711604612SMahesh Rajashekhara int aac_sync_mode;  /* Only Sync. transfer - disabled */
23885d22bbfSMahesh Rajashekhara int aac_convert_sgl = 1;	/* convert non-conformable s/g list - enabled */
2391da177e4SLinus Torvalds 
24011604612SMahesh Rajashekhara module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR);
24111604612SMahesh Rajashekhara MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode"
24211604612SMahesh Rajashekhara 	" 0=off, 1=on");
24385d22bbfSMahesh Rajashekhara module_param(aac_convert_sgl, int, S_IRUGO|S_IWUSR);
24485d22bbfSMahesh Rajashekhara MODULE_PARM_DESC(aac_convert_sgl, "Convert non-conformable s/g list"
24585d22bbfSMahesh Rajashekhara 	" 0=off, 1=on");
2469a72f976SMark Haverkamp module_param(nondasd, int, S_IRUGO|S_IWUSR);
2478ef22247SSalyzyn, Mark MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
2488ef22247SSalyzyn, Mark 	" 0=off, 1=on");
24995e852e1SSalyzyn, Mark module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
2508ef22247SSalyzyn, Mark MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n"
2518ef22247SSalyzyn, Mark 	"\tbit 0 - Disable FUA in WRITE SCSI commands\n"
2528ef22247SSalyzyn, Mark 	"\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n"
253d8e96507SLeubner, Achim 	"\tbit 2 - Disable only if Battery is protecting Cache");
2549a72f976SMark Haverkamp module_param(dacmode, int, S_IRUGO|S_IWUSR);
2558ef22247SSalyzyn, Mark MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC."
2568ef22247SSalyzyn, Mark 	" 0=off, 1=on");
2571208bab5SSalyzyn, Mark module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
2588ef22247SSalyzyn, Mark MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
2598ef22247SSalyzyn, Mark 	" adapter for foreign arrays.\n"
2608ef22247SSalyzyn, Mark 	"This is typically needed in systems that do not have a BIOS."
2618ef22247SSalyzyn, Mark 	" 0=off, 1=on");
2628ef22247SSalyzyn, Mark module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
2638ef22247SSalyzyn, Mark MODULE_PARM_DESC(msi, "IRQ handling."
2649022d375SMahesh Rajashekhara 	" 0=PIC(default), 1=MSI, 2=MSI-X)");
265404d9a90SMark Haverkamp module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
2668ef22247SSalyzyn, Mark MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
2678ef22247SSalyzyn, Mark 	" adapter to have it's kernel up and\n"
2688ef22247SSalyzyn, Mark 	"running. This is typically adjusted for large systems that do not"
2698ef22247SSalyzyn, Mark 	" have a BIOS.");
270404d9a90SMark Haverkamp module_param(aif_timeout, int, S_IRUGO|S_IWUSR);
2718ef22247SSalyzyn, Mark MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for"
2728ef22247SSalyzyn, Mark 	" applications to pick up AIFs before\n"
2738ef22247SSalyzyn, Mark 	"deregistering them. This is typically adjusted for heavily burdened"
2748ef22247SSalyzyn, Mark 	" systems.");
2751da177e4SLinus Torvalds 
2767c00ffa3SMark Haverkamp  int numacb = -1;
2777c00ffa3SMark Haverkamp  module_param(numacb, int, S_IRUGO|S_IWUSR);
2788ef22247SSalyzyn, Mark MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control"
2798ef22247SSalyzyn, Mark 	" blocks (FIB) allocated. Valid values are 512 and down. Default is"
2808ef22247SSalyzyn, Mark 	" to use suggestion from Firmware.");
2817c00ffa3SMark Haverkamp  
2827c00ffa3SMark Haverkamp  int acbsize = -1;
2837c00ffa3SMark Haverkamp  module_param(acbsize, int, S_IRUGO|S_IWUSR);
2848ef22247SSalyzyn, Mark MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)"
2858ef22247SSalyzyn, Mark 	" size. Valid values are 512, 2048, 4096 and 8192. Default is to use"
2868ef22247SSalyzyn, Mark 	" suggestion from Firmware.");
287653ba58dSMark Haverkamp 
28829c97684SSalyzyn, Mark int update_interval = 30 * 60;
28929c97684SSalyzyn, Mark module_param(update_interval, int, S_IRUGO|S_IWUSR);
2908ef22247SSalyzyn, Mark MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync"
2918ef22247SSalyzyn, Mark 	" updates issued to adapter.");
29229c97684SSalyzyn, Mark 
29329c97684SSalyzyn, Mark int check_interval = 24 * 60 * 60;
29429c97684SSalyzyn, Mark module_param(check_interval, int, S_IRUGO|S_IWUSR);
2958ef22247SSalyzyn, Mark MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health"
2968ef22247SSalyzyn, Mark 	" checks.");
29729c97684SSalyzyn, Mark 
29887f3bda3SAndrew Morton int aac_check_reset = 1;
29987f3bda3SAndrew Morton module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
30095e7a8efSPaul Bolle MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the"
3018ef22247SSalyzyn, Mark 	" adapter. a value of -1 forces the reset to adapters programmed to"
3028ef22247SSalyzyn, Mark 	" ignore it.");
30329c97684SSalyzyn, Mark 
304e37ee4beSMark Haverkamp int expose_physicals = -1;
305653ba58dSMark Haverkamp module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
3068ef22247SSalyzyn, Mark MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays."
3078ef22247SSalyzyn, Mark 	" -1=protect 0=off, 1=on");
30803d44337SMark Haverkamp 
3098ef22247SSalyzyn, Mark int aac_reset_devices;
3101208bab5SSalyzyn, Mark module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR);
3111208bab5SSalyzyn, Mark MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization.");
31203d44337SMark Haverkamp 
313d8e96507SLeubner, Achim int aac_wwn = 1;
314d8e96507SLeubner, Achim module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR);
315d8e96507SLeubner, Achim MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n"
316d8e96507SLeubner, Achim 	"\t0 - Disable\n"
317d8e96507SLeubner, Achim 	"\t1 - Array Meta Data Signature (default)\n"
318d8e96507SLeubner, Achim 	"\t2 - Adapter Serial Number");
319d8e96507SLeubner, Achim 
320d8e96507SLeubner, Achim 
32103d44337SMark Haverkamp static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
32203d44337SMark Haverkamp 		struct fib *fibptr) {
32303d44337SMark Haverkamp 	struct scsi_device *device;
32403d44337SMark Haverkamp 
32503d44337SMark Haverkamp 	if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
326c835e372SSalyzyn, Mark 		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
32703d44337SMark Haverkamp 		aac_fib_complete(fibptr);
32803d44337SMark Haverkamp 		return 0;
32903d44337SMark Haverkamp 	}
33003d44337SMark Haverkamp 	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
33103d44337SMark Haverkamp 	device = scsicmd->device;
3323ffd6c5aSRaghava Aditya Renukunta 	if (unlikely(!device)) {
33303d44337SMark Haverkamp 		dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
33403d44337SMark Haverkamp 		aac_fib_complete(fibptr);
33503d44337SMark Haverkamp 		return 0;
33603d44337SMark Haverkamp 	}
33703d44337SMark Haverkamp 	return 1;
33803d44337SMark Haverkamp }
33903d44337SMark Haverkamp 
3401da177e4SLinus Torvalds /**
3411da177e4SLinus Torvalds  *	aac_get_config_status	-	check the adapter configuration
3421da177e4SLinus Torvalds  *	@common: adapter to query
3431da177e4SLinus Torvalds  *
3441da177e4SLinus Torvalds  *	Query config status, and commit the configuration if needed.
3451da177e4SLinus Torvalds  */
3468c867b25SMark Haverkamp int aac_get_config_status(struct aac_dev *dev, int commit_flag)
3471da177e4SLinus Torvalds {
3481da177e4SLinus Torvalds 	int status = 0;
3491da177e4SLinus Torvalds 	struct fib * fibptr;
3501da177e4SLinus Torvalds 
351bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
3521da177e4SLinus Torvalds 		return -ENOMEM;
3531da177e4SLinus Torvalds 
354bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
3551da177e4SLinus Torvalds 	{
3561da177e4SLinus Torvalds 		struct aac_get_config_status *dinfo;
3571da177e4SLinus Torvalds 		dinfo = (struct aac_get_config_status *) fib_data(fibptr);
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 		dinfo->command = cpu_to_le32(VM_ContainerConfig);
3601da177e4SLinus Torvalds 		dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
3611da177e4SLinus Torvalds 		dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
3621da177e4SLinus Torvalds 	}
3631da177e4SLinus Torvalds 
364bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
3651da177e4SLinus Torvalds 			    fibptr,
3661da177e4SLinus Torvalds 			    sizeof (struct aac_get_config_status),
3671da177e4SLinus Torvalds 			    FsaNormal,
3681da177e4SLinus Torvalds 			    1, 1,
3691da177e4SLinus Torvalds 			    NULL, NULL);
3701da177e4SLinus Torvalds 	if (status < 0) {
3711da177e4SLinus Torvalds 		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
3721da177e4SLinus Torvalds 	} else {
3731da177e4SLinus Torvalds 		struct aac_get_config_status_resp *reply
3741da177e4SLinus Torvalds 		  = (struct aac_get_config_status_resp *) fib_data(fibptr);
3751da177e4SLinus Torvalds 		dprintk((KERN_WARNING
3761da177e4SLinus Torvalds 		  "aac_get_config_status: response=%d status=%d action=%d\n",
3771da177e4SLinus Torvalds 		  le32_to_cpu(reply->response),
3781da177e4SLinus Torvalds 		  le32_to_cpu(reply->status),
3791da177e4SLinus Torvalds 		  le32_to_cpu(reply->data.action)));
3801da177e4SLinus Torvalds 		if ((le32_to_cpu(reply->response) != ST_OK) ||
3811da177e4SLinus Torvalds 		     (le32_to_cpu(reply->status) != CT_OK) ||
3821da177e4SLinus Torvalds 		     (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
3831da177e4SLinus Torvalds 			printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
3841da177e4SLinus Torvalds 			status = -EINVAL;
3851da177e4SLinus Torvalds 		}
3861da177e4SLinus Torvalds 	}
387cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* Do not set XferState to zero unless receives a response from F/W */
388cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status >= 0)
389bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
390cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
3911da177e4SLinus Torvalds 	/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
3921da177e4SLinus Torvalds 	if (status >= 0) {
3931208bab5SSalyzyn, Mark 		if ((aac_commit == 1) || commit_flag) {
3941da177e4SLinus Torvalds 			struct aac_commit_config * dinfo;
395bfb35aa8SMark Haverkamp 			aac_fib_init(fibptr);
3961da177e4SLinus Torvalds 			dinfo = (struct aac_commit_config *) fib_data(fibptr);
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 			dinfo->command = cpu_to_le32(VM_ContainerConfig);
3991da177e4SLinus Torvalds 			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
4001da177e4SLinus Torvalds 
401bfb35aa8SMark Haverkamp 			status = aac_fib_send(ContainerCommand,
4021da177e4SLinus Torvalds 				    fibptr,
4031da177e4SLinus Torvalds 				    sizeof (struct aac_commit_config),
4041da177e4SLinus Torvalds 				    FsaNormal,
4051da177e4SLinus Torvalds 				    1, 1,
4061da177e4SLinus Torvalds 				    NULL, NULL);
407cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			/* Do not set XferState to zero unless
408cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			 * receives a response from F/W */
409cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			if (status >= 0)
410bfb35aa8SMark Haverkamp 				aac_fib_complete(fibptr);
4111208bab5SSalyzyn, Mark 		} else if (aac_commit == 0) {
4121da177e4SLinus Torvalds 			printk(KERN_WARNING
4131da177e4SLinus Torvalds 			  "aac_get_config_status: Foreign device configurations are being ignored\n");
4141da177e4SLinus Torvalds 		}
4151da177e4SLinus Torvalds 	}
416cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
417cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status != -ERESTARTSYS)
418bfb35aa8SMark Haverkamp 		aac_fib_free(fibptr);
4191da177e4SLinus Torvalds 	return status;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
422e3cc268fSRajashekhara, Mahesh static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
423e3cc268fSRajashekhara, Mahesh {
424e3cc268fSRajashekhara, Mahesh 	char inq_data;
425e3cc268fSRajashekhara, Mahesh 	scsi_sg_copy_to_buffer(scsicmd,  &inq_data, sizeof(inq_data));
426e3cc268fSRajashekhara, Mahesh 	if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
427e3cc268fSRajashekhara, Mahesh 		inq_data &= 0xdf;
428e3cc268fSRajashekhara, Mahesh 		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
429e3cc268fSRajashekhara, Mahesh 	}
430e3cc268fSRajashekhara, Mahesh }
431e3cc268fSRajashekhara, Mahesh 
4321da177e4SLinus Torvalds /**
4331da177e4SLinus Torvalds  *	aac_get_containers	-	list containers
4341da177e4SLinus Torvalds  *	@common: adapter to probe
4351da177e4SLinus Torvalds  *
4361da177e4SLinus Torvalds  *	Make a list of all containers on this controller
4371da177e4SLinus Torvalds  */
4381da177e4SLinus Torvalds int aac_get_containers(struct aac_dev *dev)
4391da177e4SLinus Torvalds {
4401da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
4411da177e4SLinus Torvalds 	u32 index;
4421da177e4SLinus Torvalds 	int status = 0;
4431da177e4SLinus Torvalds 	struct fib * fibptr;
4441da177e4SLinus Torvalds 	struct aac_get_container_count *dinfo;
4451da177e4SLinus Torvalds 	struct aac_get_container_count_resp *dresp;
4461da177e4SLinus Torvalds 	int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
4471da177e4SLinus Torvalds 
448bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
4491da177e4SLinus Torvalds 		return -ENOMEM;
4501da177e4SLinus Torvalds 
451bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
4521da177e4SLinus Torvalds 	dinfo = (struct aac_get_container_count *) fib_data(fibptr);
4531da177e4SLinus Torvalds 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
4541da177e4SLinus Torvalds 	dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
4551da177e4SLinus Torvalds 
456bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
4571da177e4SLinus Torvalds 		    fibptr,
4581da177e4SLinus Torvalds 		    sizeof (struct aac_get_container_count),
4591da177e4SLinus Torvalds 		    FsaNormal,
4601da177e4SLinus Torvalds 		    1, 1,
4611da177e4SLinus Torvalds 		    NULL, NULL);
4621da177e4SLinus Torvalds 	if (status >= 0) {
4631da177e4SLinus Torvalds 		dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
4641da177e4SLinus Torvalds 		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
465a7129a54SMahesh Rajashekhara 		if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
466a7129a54SMahesh Rajashekhara 		    AAC_OPTION_SUPPORTED_240_VOLUMES) {
467a7129a54SMahesh Rajashekhara 			maximum_num_containers =
468a7129a54SMahesh Rajashekhara 				le32_to_cpu(dresp->MaxSimpleVolumes);
469a7129a54SMahesh Rajashekhara 		}
470bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
4711da177e4SLinus Torvalds 	}
472cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
473cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status != -ERESTARTSYS)
474fe76df42SMark Haverkamp 		aac_fib_free(fibptr);
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds 	if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
4771da177e4SLinus Torvalds 		maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
4783ffd6c5aSRaghava Aditya Renukunta 	if (dev->fsa_dev == NULL ||
4793ffd6c5aSRaghava Aditya Renukunta 		dev->maximum_num_containers != maximum_num_containers) {
4803ffd6c5aSRaghava Aditya Renukunta 
4813ffd6c5aSRaghava Aditya Renukunta 		fsa_dev_ptr = dev->fsa_dev;
4823ffd6c5aSRaghava Aditya Renukunta 
4833ffd6c5aSRaghava Aditya Renukunta 		dev->fsa_dev = kcalloc(maximum_num_containers,
4843ffd6c5aSRaghava Aditya Renukunta 					sizeof(*fsa_dev_ptr), GFP_KERNEL);
4853ffd6c5aSRaghava Aditya Renukunta 
4863ffd6c5aSRaghava Aditya Renukunta 		kfree(fsa_dev_ptr);
4873ffd6c5aSRaghava Aditya Renukunta 		fsa_dev_ptr = NULL;
4883ffd6c5aSRaghava Aditya Renukunta 
4893ffd6c5aSRaghava Aditya Renukunta 
4903ffd6c5aSRaghava Aditya Renukunta 		if (!dev->fsa_dev)
4911da177e4SLinus Torvalds 			return -ENOMEM;
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 		dev->maximum_num_containers = maximum_num_containers;
4943ffd6c5aSRaghava Aditya Renukunta 	}
4953ffd6c5aSRaghava Aditya Renukunta 	for (index = 0; index < dev->maximum_num_containers; index++) {
4963ffd6c5aSRaghava Aditya Renukunta 		dev->fsa_dev[index].devname[0] = '\0';
4973ffd6c5aSRaghava Aditya Renukunta 		dev->fsa_dev[index].valid = 0;
4981da177e4SLinus Torvalds 
499fe76df42SMark Haverkamp 		status = aac_probe_container(dev, index);
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 		if (status < 0) {
5021da177e4SLinus Torvalds 			printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
5031da177e4SLinus Torvalds 			break;
5041da177e4SLinus Torvalds 		}
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds 	return status;
5071da177e4SLinus Torvalds }
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds static void get_container_name_callback(void *context, struct fib * fibptr)
5101da177e4SLinus Torvalds {
5111da177e4SLinus Torvalds 	struct aac_get_name_resp * get_name_reply;
5121da177e4SLinus Torvalds 	struct scsi_cmnd * scsicmd;
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
5151da177e4SLinus Torvalds 
51603d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
51703d44337SMark Haverkamp 		return;
51803d44337SMark Haverkamp 
5191da177e4SLinus Torvalds 	dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
520125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
5231da177e4SLinus Torvalds 	/* Failure is irrelevant, using default value instead */
5241da177e4SLinus Torvalds 	if ((le32_to_cpu(get_name_reply->status) == CT_OK)
5251da177e4SLinus Torvalds 	 && (get_name_reply->data[0] != '\0')) {
5261da177e4SLinus Torvalds 		char *sp = get_name_reply->data;
527b836439fSMahesh Rajashekhara 		sp[sizeof(((struct aac_get_name_resp *)NULL)->data)] = '\0';
5281da177e4SLinus Torvalds 		while (*sp == ' ')
5291da177e4SLinus Torvalds 			++sp;
5303b2946ccSMark Haverkamp 		if (*sp) {
531d4345028SFUJITA Tomonori 			struct inquiry_data inq;
5323b2946ccSMark Haverkamp 			char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
5333b2946ccSMark Haverkamp 			int count = sizeof(d);
5343b2946ccSMark Haverkamp 			char *dp = d;
5353b2946ccSMark Haverkamp 			do {
5361da177e4SLinus Torvalds 				*dp++ = (*sp) ? *sp++ : ' ';
5371da177e4SLinus Torvalds 			} while (--count > 0);
538d4345028SFUJITA Tomonori 
539d4345028SFUJITA Tomonori 			scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq));
540d4345028SFUJITA Tomonori 			memcpy(inq.inqd_pid, d, sizeof(d));
541d4345028SFUJITA Tomonori 			scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq));
5421da177e4SLinus Torvalds 		}
5433b2946ccSMark Haverkamp 	}
5443b2946ccSMark Haverkamp 
5451da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
5461da177e4SLinus Torvalds 
547bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
5488e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
5491da177e4SLinus Torvalds }
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds /**
5521da177e4SLinus Torvalds  *	aac_get_container_name	-	get container name, none blocking.
5531da177e4SLinus Torvalds  */
5549e7c349cSMark Haverkamp static int aac_get_container_name(struct scsi_cmnd * scsicmd)
5551da177e4SLinus Torvalds {
5561da177e4SLinus Torvalds 	int status;
5571da177e4SLinus Torvalds 	struct aac_get_name *dinfo;
5581da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
5591da177e4SLinus Torvalds 	struct aac_dev * dev;
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
5621da177e4SLinus Torvalds 
5636bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
5641da177e4SLinus Torvalds 
565bfb35aa8SMark Haverkamp 	aac_fib_init(cmd_fibcontext);
5661da177e4SLinus Torvalds 	dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
5691da177e4SLinus Torvalds 	dinfo->type = cpu_to_le32(CT_READ_NAME);
5709e7c349cSMark Haverkamp 	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
5711da177e4SLinus Torvalds 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
5721da177e4SLinus Torvalds 
573bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
5741da177e4SLinus Torvalds 		  cmd_fibcontext,
575fb5d40d4SMahesh Rajashekhara 		  sizeof(struct aac_get_name_resp),
5761da177e4SLinus Torvalds 		  FsaNormal,
5771da177e4SLinus Torvalds 		  0, 1,
5781da177e4SLinus Torvalds 		  (fib_callback)get_container_name_callback,
5791da177e4SLinus Torvalds 		  (void *) scsicmd);
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 	/*
5821da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
5831da177e4SLinus Torvalds 	 */
58477d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
58577d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
5861da177e4SLinus Torvalds 		return 0;
58777d644d4SMark Haverkamp 	}
5881da177e4SLinus Torvalds 
589bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
590bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
5911da177e4SLinus Torvalds 	return -1;
5921da177e4SLinus Torvalds }
5931da177e4SLinus Torvalds 
594fe76df42SMark Haverkamp static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
595fe76df42SMark Haverkamp {
596fe76df42SMark Haverkamp 	struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
597fe76df42SMark Haverkamp 
5981a655040SSalyzyn, Mark 	if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))
599fe76df42SMark Haverkamp 		return aac_scsi_cmd(scsicmd);
600fe76df42SMark Haverkamp 
601fe76df42SMark Haverkamp 	scsicmd->result = DID_NO_CONNECT << 16;
602fe76df42SMark Haverkamp 	scsicmd->scsi_done(scsicmd);
603fe76df42SMark Haverkamp 	return 0;
604fe76df42SMark Haverkamp }
605fe76df42SMark Haverkamp 
6061a655040SSalyzyn, Mark static void _aac_probe_container2(void * context, struct fib * fibptr)
607fe76df42SMark Haverkamp {
60803d44337SMark Haverkamp 	struct fsa_dev_info *fsa_dev_ptr;
609fe76df42SMark Haverkamp 	int (*callback)(struct scsi_cmnd *);
61003d44337SMark Haverkamp 	struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
61103d44337SMark Haverkamp 
61203d44337SMark Haverkamp 
6131a655040SSalyzyn, Mark 	if (!aac_valid_context(scsicmd, fibptr))
6141a655040SSalyzyn, Mark 		return;
615fe76df42SMark Haverkamp 
616fe76df42SMark Haverkamp 	scsicmd->SCp.Status = 0;
6171a655040SSalyzyn, Mark 	fsa_dev_ptr = fibptr->dev->fsa_dev;
618fe76df42SMark Haverkamp 	if (fsa_dev_ptr) {
619fe76df42SMark Haverkamp 		struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
620fe76df42SMark Haverkamp 		fsa_dev_ptr += scmd_id(scsicmd);
621fe76df42SMark Haverkamp 
622fe76df42SMark Haverkamp 		if ((le32_to_cpu(dresp->status) == ST_OK) &&
623fe76df42SMark Haverkamp 		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
624fe76df42SMark Haverkamp 		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
625b836439fSMahesh Rajashekhara 			if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 &
626b836439fSMahesh Rajashekhara 			    AAC_OPTION_VARIABLE_BLOCK_SIZE)) {
627b836439fSMahesh Rajashekhara 				dresp->mnt[0].fileinfo.bdevinfo.block_size = 0x200;
628b836439fSMahesh Rajashekhara 				fsa_dev_ptr->block_size = 0x200;
629b836439fSMahesh Rajashekhara 			} else {
630b836439fSMahesh Rajashekhara 				fsa_dev_ptr->block_size =
631b836439fSMahesh Rajashekhara 					le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size);
632b836439fSMahesh Rajashekhara 			}
633fe76df42SMark Haverkamp 			fsa_dev_ptr->valid = 1;
634655d722cSMark Salyzyn 			/* sense_key holds the current state of the spin-up */
635655d722cSMark Salyzyn 			if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
636655d722cSMark Salyzyn 				fsa_dev_ptr->sense_data.sense_key = NOT_READY;
637655d722cSMark Salyzyn 			else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
638655d722cSMark Salyzyn 				fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
639fe76df42SMark Haverkamp 			fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
640fe76df42SMark Haverkamp 			fsa_dev_ptr->size
641fe76df42SMark Haverkamp 			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
642fe76df42SMark Haverkamp 			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
643fe76df42SMark Haverkamp 			fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
644fe76df42SMark Haverkamp 		}
645fe76df42SMark Haverkamp 		if ((fsa_dev_ptr->valid & 1) == 0)
646fe76df42SMark Haverkamp 			fsa_dev_ptr->valid = 0;
647fe76df42SMark Haverkamp 		scsicmd->SCp.Status = le32_to_cpu(dresp->count);
648fe76df42SMark Haverkamp 	}
649fe76df42SMark Haverkamp 	aac_fib_complete(fibptr);
650fe76df42SMark Haverkamp 	aac_fib_free(fibptr);
651fe76df42SMark Haverkamp 	callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
652fe76df42SMark Haverkamp 	scsicmd->SCp.ptr = NULL;
6531a655040SSalyzyn, Mark 	(*callback)(scsicmd);
6541a655040SSalyzyn, Mark 	return;
655fe76df42SMark Haverkamp }
656fe76df42SMark Haverkamp 
6571a655040SSalyzyn, Mark static void _aac_probe_container1(void * context, struct fib * fibptr)
658fe76df42SMark Haverkamp {
659fe76df42SMark Haverkamp 	struct scsi_cmnd * scsicmd;
660fe76df42SMark Haverkamp 	struct aac_mount * dresp;
661fe76df42SMark Haverkamp 	struct aac_query_mount *dinfo;
662fe76df42SMark Haverkamp 	int status;
663fe76df42SMark Haverkamp 
664fe76df42SMark Haverkamp 	dresp = (struct aac_mount *) fib_data(fibptr);
665b836439fSMahesh Rajashekhara 	if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 &
666b836439fSMahesh Rajashekhara 	    AAC_OPTION_VARIABLE_BLOCK_SIZE))
667fe76df42SMark Haverkamp 		dresp->mnt[0].capacityhigh = 0;
668fe76df42SMark Haverkamp 	if ((le32_to_cpu(dresp->status) != ST_OK) ||
6691a655040SSalyzyn, Mark 	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
6701a655040SSalyzyn, Mark 		_aac_probe_container2(context, fibptr);
6711a655040SSalyzyn, Mark 		return;
6721a655040SSalyzyn, Mark 	}
673fe76df42SMark Haverkamp 	scsicmd = (struct scsi_cmnd *) context;
674fe76df42SMark Haverkamp 
67503d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
6761a655040SSalyzyn, Mark 		return;
67703d44337SMark Haverkamp 
678fe76df42SMark Haverkamp 	aac_fib_init(fibptr);
679fe76df42SMark Haverkamp 
680fe76df42SMark Haverkamp 	dinfo = (struct aac_query_mount *)fib_data(fibptr);
681fe76df42SMark Haverkamp 
682b836439fSMahesh Rajashekhara 	if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
683b836439fSMahesh Rajashekhara 	    AAC_OPTION_VARIABLE_BLOCK_SIZE)
684b836439fSMahesh Rajashekhara 		dinfo->command = cpu_to_le32(VM_NameServeAllBlk);
685b836439fSMahesh Rajashekhara 	else
686fe76df42SMark Haverkamp 		dinfo->command = cpu_to_le32(VM_NameServe64);
687b836439fSMahesh Rajashekhara 
688fe76df42SMark Haverkamp 	dinfo->count = cpu_to_le32(scmd_id(scsicmd));
689fe76df42SMark Haverkamp 	dinfo->type = cpu_to_le32(FT_FILESYS);
690fe76df42SMark Haverkamp 
691fe76df42SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
692fe76df42SMark Haverkamp 			  fibptr,
693fe76df42SMark Haverkamp 			  sizeof(struct aac_query_mount),
694fe76df42SMark Haverkamp 			  FsaNormal,
695fe76df42SMark Haverkamp 			  0, 1,
6961a655040SSalyzyn, Mark 			  _aac_probe_container2,
697fe76df42SMark Haverkamp 			  (void *) scsicmd);
698fe76df42SMark Haverkamp 	/*
699fe76df42SMark Haverkamp 	 *	Check that the command queued to the controller
700fe76df42SMark Haverkamp 	 */
7011a655040SSalyzyn, Mark 	if (status == -EINPROGRESS)
702fe76df42SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
7031a655040SSalyzyn, Mark 	else if (status < 0) {
704fe76df42SMark Haverkamp 		/* Inherit results from VM_NameServe, if any */
705fe76df42SMark Haverkamp 		dresp->status = cpu_to_le32(ST_OK);
7061a655040SSalyzyn, Mark 		_aac_probe_container2(context, fibptr);
707fe76df42SMark Haverkamp 	}
708fe76df42SMark Haverkamp }
709fe76df42SMark Haverkamp 
710fe76df42SMark Haverkamp static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
711fe76df42SMark Haverkamp {
712fe76df42SMark Haverkamp 	struct fib * fibptr;
713fe76df42SMark Haverkamp 	int status = -ENOMEM;
714fe76df42SMark Haverkamp 
715fe76df42SMark Haverkamp 	if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
716fe76df42SMark Haverkamp 		struct aac_query_mount *dinfo;
717fe76df42SMark Haverkamp 
718fe76df42SMark Haverkamp 		aac_fib_init(fibptr);
719fe76df42SMark Haverkamp 
720fe76df42SMark Haverkamp 		dinfo = (struct aac_query_mount *)fib_data(fibptr);
721fe76df42SMark Haverkamp 
722b836439fSMahesh Rajashekhara 		if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
723b836439fSMahesh Rajashekhara 		    AAC_OPTION_VARIABLE_BLOCK_SIZE)
724b836439fSMahesh Rajashekhara 			dinfo->command = cpu_to_le32(VM_NameServeAllBlk);
725b836439fSMahesh Rajashekhara 		else
726fe76df42SMark Haverkamp 			dinfo->command = cpu_to_le32(VM_NameServe);
727b836439fSMahesh Rajashekhara 
728fe76df42SMark Haverkamp 		dinfo->count = cpu_to_le32(scmd_id(scsicmd));
729fe76df42SMark Haverkamp 		dinfo->type = cpu_to_le32(FT_FILESYS);
730fe76df42SMark Haverkamp 		scsicmd->SCp.ptr = (char *)callback;
731fe76df42SMark Haverkamp 
732fe76df42SMark Haverkamp 		status = aac_fib_send(ContainerCommand,
733fe76df42SMark Haverkamp 			  fibptr,
734fe76df42SMark Haverkamp 			  sizeof(struct aac_query_mount),
735fe76df42SMark Haverkamp 			  FsaNormal,
736fe76df42SMark Haverkamp 			  0, 1,
7371a655040SSalyzyn, Mark 			  _aac_probe_container1,
738fe76df42SMark Haverkamp 			  (void *) scsicmd);
739fe76df42SMark Haverkamp 		/*
740fe76df42SMark Haverkamp 		 *	Check that the command queued to the controller
741fe76df42SMark Haverkamp 		 */
742fe76df42SMark Haverkamp 		if (status == -EINPROGRESS) {
743fe76df42SMark Haverkamp 			scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
744fe76df42SMark Haverkamp 			return 0;
745fe76df42SMark Haverkamp 		}
746fe76df42SMark Haverkamp 		if (status < 0) {
747fe76df42SMark Haverkamp 			scsicmd->SCp.ptr = NULL;
748fe76df42SMark Haverkamp 			aac_fib_complete(fibptr);
749fe76df42SMark Haverkamp 			aac_fib_free(fibptr);
750fe76df42SMark Haverkamp 		}
751fe76df42SMark Haverkamp 	}
752fe76df42SMark Haverkamp 	if (status < 0) {
753fe76df42SMark Haverkamp 		struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
754fe76df42SMark Haverkamp 		if (fsa_dev_ptr) {
755fe76df42SMark Haverkamp 			fsa_dev_ptr += scmd_id(scsicmd);
756fe76df42SMark Haverkamp 			if ((fsa_dev_ptr->valid & 1) == 0) {
757fe76df42SMark Haverkamp 				fsa_dev_ptr->valid = 0;
758fe76df42SMark Haverkamp 				return (*callback)(scsicmd);
759fe76df42SMark Haverkamp 			}
760fe76df42SMark Haverkamp 		}
761fe76df42SMark Haverkamp 	}
762fe76df42SMark Haverkamp 	return status;
763fe76df42SMark Haverkamp }
764fe76df42SMark Haverkamp 
7651da177e4SLinus Torvalds /**
766bfb35aa8SMark Haverkamp  *	aac_probe_container		-	query a logical volume
7671da177e4SLinus Torvalds  *	@dev: device to query
7681da177e4SLinus Torvalds  *	@cid: container identifier
7691da177e4SLinus Torvalds  *
7701da177e4SLinus Torvalds  *	Queries the controller about the given volume. The volume information
7711da177e4SLinus Torvalds  *	is updated in the struct fsa_dev_info structure rather than returned.
7721da177e4SLinus Torvalds  */
773fe76df42SMark Haverkamp static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
774fe76df42SMark Haverkamp {
775fe76df42SMark Haverkamp 	scsicmd->device = NULL;
776fe76df42SMark Haverkamp 	return 0;
777fe76df42SMark Haverkamp }
7781da177e4SLinus Torvalds 
779bfb35aa8SMark Haverkamp int aac_probe_container(struct aac_dev *dev, int cid)
7801da177e4SLinus Torvalds {
781fe76df42SMark Haverkamp 	struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
782fe76df42SMark Haverkamp 	struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
7831da177e4SLinus Torvalds 	int status;
7841da177e4SLinus Torvalds 
785fe76df42SMark Haverkamp 	if (!scsicmd || !scsidev) {
786fe76df42SMark Haverkamp 		kfree(scsicmd);
787fe76df42SMark Haverkamp 		kfree(scsidev);
78890ee3466SMark Haverkamp 		return -ENOMEM;
7891da177e4SLinus Torvalds 	}
790fe76df42SMark Haverkamp 	scsicmd->list.next = NULL;
7911a655040SSalyzyn, Mark 	scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;
7921da177e4SLinus Torvalds 
793fe76df42SMark Haverkamp 	scsicmd->device = scsidev;
794fe76df42SMark Haverkamp 	scsidev->sdev_state = 0;
795fe76df42SMark Haverkamp 	scsidev->id = cid;
796fe76df42SMark Haverkamp 	scsidev->host = dev->scsi_host_ptr;
7971da177e4SLinus Torvalds 
798fe76df42SMark Haverkamp 	if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
799fe76df42SMark Haverkamp 		while (scsicmd->device == scsidev)
800fe76df42SMark Haverkamp 			schedule();
801802ae2f0SSalyzyn, Mark 	kfree(scsidev);
802fe76df42SMark Haverkamp 	status = scsicmd->SCp.Status;
803fe76df42SMark Haverkamp 	kfree(scsicmd);
8041da177e4SLinus Torvalds 	return status;
8051da177e4SLinus Torvalds }
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds /* Local Structure to set SCSI inquiry data strings */
8081da177e4SLinus Torvalds struct scsi_inq {
8091da177e4SLinus Torvalds 	char vid[8];         /* Vendor ID */
8101da177e4SLinus Torvalds 	char pid[16];        /* Product ID */
8111da177e4SLinus Torvalds 	char prl[4];         /* Product Revision Level */
8121da177e4SLinus Torvalds };
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds /**
8151da177e4SLinus Torvalds  *	InqStrCopy	-	string merge
8161da177e4SLinus Torvalds  *	@a:	string to copy from
8171da177e4SLinus Torvalds  *	@b:	string to copy to
8181da177e4SLinus Torvalds  *
8191da177e4SLinus Torvalds  *	Copy a String from one location to another
8201da177e4SLinus Torvalds  *	without copying \0
8211da177e4SLinus Torvalds  */
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds static void inqstrcpy(char *a, char *b)
8241da177e4SLinus Torvalds {
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds 	while (*a != (char)0)
8271da177e4SLinus Torvalds 		*b++ = *a++;
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds static char *container_types[] = {
8311da177e4SLinus Torvalds 	"None",
8321da177e4SLinus Torvalds 	"Volume",
8331da177e4SLinus Torvalds 	"Mirror",
8341da177e4SLinus Torvalds 	"Stripe",
8351da177e4SLinus Torvalds 	"RAID5",
8361da177e4SLinus Torvalds 	"SSRW",
8371da177e4SLinus Torvalds 	"SSRO",
8381da177e4SLinus Torvalds 	"Morph",
8391da177e4SLinus Torvalds 	"Legacy",
8401da177e4SLinus Torvalds 	"RAID4",
8411da177e4SLinus Torvalds 	"RAID10",
8421da177e4SLinus Torvalds 	"RAID00",
8431da177e4SLinus Torvalds 	"V-MIRRORS",
8441da177e4SLinus Torvalds 	"PSEUDO R4",
8451da177e4SLinus Torvalds 	"RAID50",
84684971738SMark Haverkamp 	"RAID5D",
84784971738SMark Haverkamp 	"RAID5D0",
84884971738SMark Haverkamp 	"RAID1E",
84984971738SMark Haverkamp 	"RAID6",
85084971738SMark Haverkamp 	"RAID60",
8511da177e4SLinus Torvalds 	"Unknown"
8521da177e4SLinus Torvalds };
8531da177e4SLinus Torvalds 
85417eaaceeSSalyzyn, Mark char * get_container_type(unsigned tindex)
85517eaaceeSSalyzyn, Mark {
85617eaaceeSSalyzyn, Mark 	if (tindex >= ARRAY_SIZE(container_types))
85717eaaceeSSalyzyn, Mark 		tindex = ARRAY_SIZE(container_types) - 1;
85817eaaceeSSalyzyn, Mark 	return container_types[tindex];
85917eaaceeSSalyzyn, Mark }
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds /* Function: setinqstr
8621da177e4SLinus Torvalds  *
8631da177e4SLinus Torvalds  * Arguments: [1] pointer to void [1] int
8641da177e4SLinus Torvalds  *
8651da177e4SLinus Torvalds  * Purpose: Sets SCSI inquiry data strings for vendor, product
86625985edcSLucas De Marchi  * and revision level. Allows strings to be set in platform dependent
86725985edcSLucas De Marchi  * files instead of in OS dependent driver source.
8681da177e4SLinus Torvalds  */
8691da177e4SLinus Torvalds 
870794d0601SMark Haverkamp static void setinqstr(struct aac_dev *dev, void *data, int tindex)
8711da177e4SLinus Torvalds {
8721da177e4SLinus Torvalds 	struct scsi_inq *str;
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
875794d0601SMark Haverkamp 	memset(str, ' ', sizeof(*str));
876794d0601SMark Haverkamp 
877794d0601SMark Haverkamp 	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
878794d0601SMark Haverkamp 		char * cp = dev->supplement_adapter_info.AdapterTypeText;
8793bc8070fSSalyzyn, Mark 		int c;
8803bc8070fSSalyzyn, Mark 		if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
8813bc8070fSSalyzyn, Mark 			inqstrcpy("SMC", str->vid);
8823bc8070fSSalyzyn, Mark 		else {
8833bc8070fSSalyzyn, Mark 			c = sizeof(str->vid);
884794d0601SMark Haverkamp 			while (*cp && *cp != ' ' && --c)
885794d0601SMark Haverkamp 				++cp;
886794d0601SMark Haverkamp 			c = *cp;
887794d0601SMark Haverkamp 			*cp = '\0';
888794d0601SMark Haverkamp 			inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
889794d0601SMark Haverkamp 				   str->vid);
890794d0601SMark Haverkamp 			*cp = c;
891794d0601SMark Haverkamp 			while (*cp && *cp != ' ')
892794d0601SMark Haverkamp 				++cp;
8933bc8070fSSalyzyn, Mark 		}
894794d0601SMark Haverkamp 		while (*cp == ' ')
895794d0601SMark Haverkamp 			++cp;
896794d0601SMark Haverkamp 		/* last six chars reserved for vol type */
897794d0601SMark Haverkamp 		c = 0;
898794d0601SMark Haverkamp 		if (strlen(cp) > sizeof(str->pid)) {
899794d0601SMark Haverkamp 			c = cp[sizeof(str->pid)];
900794d0601SMark Haverkamp 			cp[sizeof(str->pid)] = '\0';
901794d0601SMark Haverkamp 		}
902794d0601SMark Haverkamp 		inqstrcpy (cp, str->pid);
903794d0601SMark Haverkamp 		if (c)
904794d0601SMark Haverkamp 			cp[sizeof(str->pid)] = c;
905794d0601SMark Haverkamp 	} else {
906794d0601SMark Haverkamp 		struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds 		inqstrcpy (mp->vname, str->vid);
909794d0601SMark Haverkamp 		/* last six chars reserved for vol type */
910794d0601SMark Haverkamp 		inqstrcpy (mp->model, str->pid);
911794d0601SMark Haverkamp 	}
9121da177e4SLinus Torvalds 
9136391a113STobias Klauser 	if (tindex < ARRAY_SIZE(container_types)){
9141da177e4SLinus Torvalds 		char *findit = str->pid;
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds 		for ( ; *findit != ' '; findit++); /* walk till we find a space */
9171da177e4SLinus Torvalds 		/* RAID is superfluous in the context of a RAID device */
9181da177e4SLinus Torvalds 		if (memcmp(findit-4, "RAID", 4) == 0)
9191da177e4SLinus Torvalds 			*(findit -= 4) = ' ';
920794d0601SMark Haverkamp 		if (((findit - str->pid) + strlen(container_types[tindex]))
921794d0601SMark Haverkamp 		 < (sizeof(str->pid) + sizeof(str->prl)))
9221da177e4SLinus Torvalds 			inqstrcpy (container_types[tindex], findit + 1);
9231da177e4SLinus Torvalds 	}
9241da177e4SLinus Torvalds 	inqstrcpy ("V1.0", str->prl);
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds 
92788e2f98eSSalyzyn, Mark static void get_container_serial_callback(void *context, struct fib * fibptr)
92888e2f98eSSalyzyn, Mark {
92988e2f98eSSalyzyn, Mark 	struct aac_get_serial_resp * get_serial_reply;
93088e2f98eSSalyzyn, Mark 	struct scsi_cmnd * scsicmd;
93188e2f98eSSalyzyn, Mark 
93288e2f98eSSalyzyn, Mark 	BUG_ON(fibptr == NULL);
93388e2f98eSSalyzyn, Mark 
93488e2f98eSSalyzyn, Mark 	scsicmd = (struct scsi_cmnd *) context;
93588e2f98eSSalyzyn, Mark 	if (!aac_valid_context(scsicmd, fibptr))
93688e2f98eSSalyzyn, Mark 		return;
93788e2f98eSSalyzyn, Mark 
93888e2f98eSSalyzyn, Mark 	get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
93988e2f98eSSalyzyn, Mark 	/* Failure is irrelevant, using default value instead */
94088e2f98eSSalyzyn, Mark 	if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
9415d910649SMahesh Rajashekhara 		/*Check to see if it's for VPD 0x83 or 0x80 */
9425d910649SMahesh Rajashekhara 		if (scsicmd->cmnd[2] == 0x83) {
9435d910649SMahesh Rajashekhara 			/* vpd page 0x83 - Device Identification Page */
9445d910649SMahesh Rajashekhara 			int i;
9455d910649SMahesh Rajashekhara 			TVPD_Page83 VPDPage83Data;
9465d910649SMahesh Rajashekhara 
9475d910649SMahesh Rajashekhara 			memset(((u8 *)&VPDPage83Data), 0,
9485d910649SMahesh Rajashekhara 			       sizeof(VPDPage83Data));
9495d910649SMahesh Rajashekhara 
9505d910649SMahesh Rajashekhara 			/* DIRECT_ACCESS_DEVIC */
9515d910649SMahesh Rajashekhara 			VPDPage83Data.DeviceType = 0;
9525d910649SMahesh Rajashekhara 			/* DEVICE_CONNECTED */
9535d910649SMahesh Rajashekhara 			VPDPage83Data.DeviceTypeQualifier = 0;
9545d910649SMahesh Rajashekhara 			/* VPD_DEVICE_IDENTIFIERS */
9555d910649SMahesh Rajashekhara 			VPDPage83Data.PageCode = 0x83;
9565d910649SMahesh Rajashekhara 			VPDPage83Data.Reserved = 0;
9575d910649SMahesh Rajashekhara 			VPDPage83Data.PageLength =
9585d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType1) +
9595d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType2);
9605d910649SMahesh Rajashekhara 
9615d910649SMahesh Rajashekhara 			/* T10 Vendor Identifier Field Format */
9625d910649SMahesh Rajashekhara 			/* VpdCodeSetAscii */
9635d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType1.CodeSet = 2;
9645d910649SMahesh Rajashekhara 			/* VpdIdentifierTypeVendorId */
9655d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType1.IdentifierType = 1;
9665d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType1.IdentifierLength =
9675d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType1) - 4;
9685d910649SMahesh Rajashekhara 
9695d910649SMahesh Rajashekhara 			/* "ADAPTEC " for adaptec */
9705d910649SMahesh Rajashekhara 			memcpy(VPDPage83Data.IdDescriptorType1.VendId,
9715d910649SMahesh Rajashekhara 				"ADAPTEC ",
9725d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType1.VendId));
9735d910649SMahesh Rajashekhara 			memcpy(VPDPage83Data.IdDescriptorType1.ProductId,
9745d910649SMahesh Rajashekhara 				"ARRAY           ",
9755d910649SMahesh Rajashekhara 				sizeof(
9765d910649SMahesh Rajashekhara 				VPDPage83Data.IdDescriptorType1.ProductId));
9775d910649SMahesh Rajashekhara 
9785d910649SMahesh Rajashekhara 			/* Convert to ascii based serial number.
9795d910649SMahesh Rajashekhara 			 * The LSB is the the end.
9805d910649SMahesh Rajashekhara 			 */
9815d910649SMahesh Rajashekhara 			for (i = 0; i < 8; i++) {
9825d910649SMahesh Rajashekhara 				u8 temp =
9835d910649SMahesh Rajashekhara 					(u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF);
9845d910649SMahesh Rajashekhara 				if (temp  > 0x9) {
9855d910649SMahesh Rajashekhara 					VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
9865d910649SMahesh Rajashekhara 							'A' + (temp - 0xA);
9875d910649SMahesh Rajashekhara 				} else {
9885d910649SMahesh Rajashekhara 					VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
9895d910649SMahesh Rajashekhara 							'0' + temp;
9905d910649SMahesh Rajashekhara 				}
9915d910649SMahesh Rajashekhara 			}
9925d910649SMahesh Rajashekhara 
9935d910649SMahesh Rajashekhara 			/* VpdCodeSetBinary */
9945d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.CodeSet = 1;
9955d910649SMahesh Rajashekhara 			/* VpdIdentifierTypeEUI64 */
9965d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.IdentifierType = 2;
9975d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.IdentifierLength =
9985d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType2) - 4;
9995d910649SMahesh Rajashekhara 
10005d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0;
10015d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0;
10025d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0;
10035d910649SMahesh Rajashekhara 
10045d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.Serial =
10055d910649SMahesh Rajashekhara 							get_serial_reply->uid;
10065d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0;
10075d910649SMahesh Rajashekhara 
10085d910649SMahesh Rajashekhara 			/* Move the inquiry data to the response buffer. */
10095d910649SMahesh Rajashekhara 			scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data,
10105d910649SMahesh Rajashekhara 						 sizeof(VPDPage83Data));
10115d910649SMahesh Rajashekhara 		} else {
10125d910649SMahesh Rajashekhara 			/* It must be for VPD 0x80 */
101388e2f98eSSalyzyn, Mark 			char sp[13];
101488e2f98eSSalyzyn, Mark 			/* EVPD bit set */
101588e2f98eSSalyzyn, Mark 			sp[0] = INQD_PDT_DA;
101688e2f98eSSalyzyn, Mark 			sp[1] = scsicmd->cmnd[2];
101788e2f98eSSalyzyn, Mark 			sp[2] = 0;
101888e2f98eSSalyzyn, Mark 			sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
101988e2f98eSSalyzyn, Mark 				le32_to_cpu(get_serial_reply->uid));
10205d910649SMahesh Rajashekhara 			scsi_sg_copy_from_buffer(scsicmd, sp,
10215d910649SMahesh Rajashekhara 						 sizeof(sp));
10225d910649SMahesh Rajashekhara 		}
102388e2f98eSSalyzyn, Mark 	}
102488e2f98eSSalyzyn, Mark 
102588e2f98eSSalyzyn, Mark 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
102688e2f98eSSalyzyn, Mark 
102788e2f98eSSalyzyn, Mark 	aac_fib_complete(fibptr);
102888e2f98eSSalyzyn, Mark 	scsicmd->scsi_done(scsicmd);
102988e2f98eSSalyzyn, Mark }
103088e2f98eSSalyzyn, Mark 
103188e2f98eSSalyzyn, Mark /**
103288e2f98eSSalyzyn, Mark  *	aac_get_container_serial - get container serial, none blocking.
103388e2f98eSSalyzyn, Mark  */
103488e2f98eSSalyzyn, Mark static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
103588e2f98eSSalyzyn, Mark {
103688e2f98eSSalyzyn, Mark 	int status;
103788e2f98eSSalyzyn, Mark 	struct aac_get_serial *dinfo;
103888e2f98eSSalyzyn, Mark 	struct fib * cmd_fibcontext;
103988e2f98eSSalyzyn, Mark 	struct aac_dev * dev;
104088e2f98eSSalyzyn, Mark 
104188e2f98eSSalyzyn, Mark 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
104288e2f98eSSalyzyn, Mark 
10436bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
104488e2f98eSSalyzyn, Mark 
104588e2f98eSSalyzyn, Mark 	aac_fib_init(cmd_fibcontext);
104688e2f98eSSalyzyn, Mark 	dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
104788e2f98eSSalyzyn, Mark 
104888e2f98eSSalyzyn, Mark 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
104988e2f98eSSalyzyn, Mark 	dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
105088e2f98eSSalyzyn, Mark 	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
105188e2f98eSSalyzyn, Mark 
105288e2f98eSSalyzyn, Mark 	status = aac_fib_send(ContainerCommand,
105388e2f98eSSalyzyn, Mark 		  cmd_fibcontext,
1054fb5d40d4SMahesh Rajashekhara 		  sizeof(struct aac_get_serial_resp),
105588e2f98eSSalyzyn, Mark 		  FsaNormal,
105688e2f98eSSalyzyn, Mark 		  0, 1,
105788e2f98eSSalyzyn, Mark 		  (fib_callback) get_container_serial_callback,
105888e2f98eSSalyzyn, Mark 		  (void *) scsicmd);
105988e2f98eSSalyzyn, Mark 
106088e2f98eSSalyzyn, Mark 	/*
106188e2f98eSSalyzyn, Mark 	 *	Check that the command queued to the controller
106288e2f98eSSalyzyn, Mark 	 */
106388e2f98eSSalyzyn, Mark 	if (status == -EINPROGRESS) {
106488e2f98eSSalyzyn, Mark 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
106588e2f98eSSalyzyn, Mark 		return 0;
106688e2f98eSSalyzyn, Mark 	}
106788e2f98eSSalyzyn, Mark 
106888e2f98eSSalyzyn, Mark 	printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
106988e2f98eSSalyzyn, Mark 	aac_fib_complete(cmd_fibcontext);
107088e2f98eSSalyzyn, Mark 	return -1;
107188e2f98eSSalyzyn, Mark }
107288e2f98eSSalyzyn, Mark 
107388e2f98eSSalyzyn, Mark /* Function: setinqserial
107488e2f98eSSalyzyn, Mark  *
107588e2f98eSSalyzyn, Mark  * Arguments: [1] pointer to void [1] int
107688e2f98eSSalyzyn, Mark  *
107788e2f98eSSalyzyn, Mark  * Purpose: Sets SCSI Unit Serial number.
107888e2f98eSSalyzyn, Mark  *          This is a fake. We should read a proper
107988e2f98eSSalyzyn, Mark  *          serial number from the container. <SuSE>But
108088e2f98eSSalyzyn, Mark  *          without docs it's quite hard to do it :-)
108188e2f98eSSalyzyn, Mark  *          So this will have to do in the meantime.</SuSE>
108288e2f98eSSalyzyn, Mark  */
108388e2f98eSSalyzyn, Mark 
108488e2f98eSSalyzyn, Mark static int setinqserial(struct aac_dev *dev, void *data, int cid)
108588e2f98eSSalyzyn, Mark {
108688e2f98eSSalyzyn, Mark 	/*
108788e2f98eSSalyzyn, Mark 	 *	This breaks array migration.
108888e2f98eSSalyzyn, Mark 	 */
108988e2f98eSSalyzyn, Mark 	return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
109088e2f98eSSalyzyn, Mark 			le32_to_cpu(dev->adapter_info.serial[0]), cid);
109188e2f98eSSalyzyn, Mark }
109288e2f98eSSalyzyn, Mark 
10938e31e607SSalyzyn, Mark static inline void set_sense(struct sense_data *sense_data, u8 sense_key,
10948e31e607SSalyzyn, Mark 	u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer)
10951da177e4SLinus Torvalds {
10968e31e607SSalyzyn, Mark 	u8 *sense_buf = (u8 *)sense_data;
10978e31e607SSalyzyn, Mark 	/* Sense data valid, err code 70h */
10988e31e607SSalyzyn, Mark 	sense_buf[0] = 0x70; /* No info field */
10991da177e4SLinus Torvalds 	sense_buf[1] = 0;	/* Segment number, always zero */
11001da177e4SLinus Torvalds 
11011da177e4SLinus Torvalds 	sense_buf[2] = sense_key;	/* Sense key */
11021da177e4SLinus Torvalds 
11031da177e4SLinus Torvalds 	sense_buf[12] = sense_code;	/* Additional sense code */
11041da177e4SLinus Torvalds 	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */
11058e31e607SSalyzyn, Mark 
11061da177e4SLinus Torvalds 	if (sense_key == ILLEGAL_REQUEST) {
11078e31e607SSalyzyn, Mark 		sense_buf[7] = 10;	/* Additional sense length */
11081da177e4SLinus Torvalds 
11098e31e607SSalyzyn, Mark 		sense_buf[15] = bit_pointer;
11101da177e4SLinus Torvalds 		/* Illegal parameter is in the parameter block */
11111da177e4SLinus Torvalds 		if (sense_code == SENCODE_INVALID_CDB_FIELD)
11128e31e607SSalyzyn, Mark 			sense_buf[15] |= 0xc0;/* Std sense key specific field */
11131da177e4SLinus Torvalds 		/* Illegal parameter is in the CDB block */
11141da177e4SLinus Torvalds 		sense_buf[16] = field_pointer >> 8;	/* MSB */
11151da177e4SLinus Torvalds 		sense_buf[17] = field_pointer;		/* LSB */
11168e31e607SSalyzyn, Mark 	} else
11178e31e607SSalyzyn, Mark 		sense_buf[7] = 6;	/* Additional sense length */
11181da177e4SLinus Torvalds }
11191da177e4SLinus Torvalds 
1120e8f32de5SMark Haverkamp static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
1121e8f32de5SMark Haverkamp {
1122e8f32de5SMark Haverkamp 	if (lba & 0xffffffff00000000LL) {
1123e8f32de5SMark Haverkamp 		int cid = scmd_id(cmd);
1124e8f32de5SMark Haverkamp 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
1125e8f32de5SMark Haverkamp 		cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1126e8f32de5SMark Haverkamp 			SAM_STAT_CHECK_CONDITION;
11278e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
11288e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
11298e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
1130e8f32de5SMark Haverkamp 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
11313ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
11323ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
1133e8f32de5SMark Haverkamp 		cmd->scsi_done(cmd);
1134e8f32de5SMark Haverkamp 		return 1;
1135e8f32de5SMark Haverkamp 	}
1136e8f32de5SMark Haverkamp 	return 0;
1137e8f32de5SMark Haverkamp }
1138e8f32de5SMark Haverkamp 
1139e8f32de5SMark Haverkamp static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
1140e8f32de5SMark Haverkamp {
1141e8f32de5SMark Haverkamp 	return 0;
1142e8f32de5SMark Haverkamp }
1143e8f32de5SMark Haverkamp 
1144e8f32de5SMark Haverkamp static void io_callback(void *context, struct fib * fibptr);
1145e8f32de5SMark Haverkamp 
1146e8f32de5SMark Haverkamp static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1147e8f32de5SMark Haverkamp {
114885d22bbfSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
114985d22bbfSMahesh Rajashekhara 	u16 fibsize, command;
11500b433447SMahesh Rajashekhara 	long ret;
115185d22bbfSMahesh Rajashekhara 
1152e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1153d1ef4da8SRaghava Aditya Renukunta 	if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
1154d1ef4da8SRaghava Aditya Renukunta 		dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) &&
1155d1ef4da8SRaghava Aditya Renukunta 		!dev->sync_mode) {
115685d22bbfSMahesh Rajashekhara 		struct aac_raw_io2 *readcmd2;
115785d22bbfSMahesh Rajashekhara 		readcmd2 = (struct aac_raw_io2 *) fib_data(fib);
115885d22bbfSMahesh Rajashekhara 		memset(readcmd2, 0, sizeof(struct aac_raw_io2));
115985d22bbfSMahesh Rajashekhara 		readcmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff));
116085d22bbfSMahesh Rajashekhara 		readcmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1161b836439fSMahesh Rajashekhara 		readcmd2->byteCount = cpu_to_le32(count *
1162b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
116385d22bbfSMahesh Rajashekhara 		readcmd2->cid = cpu_to_le16(scmd_id(cmd));
116485d22bbfSMahesh Rajashekhara 		readcmd2->flags = cpu_to_le16(RIO2_IO_TYPE_READ);
11650b433447SMahesh Rajashekhara 		ret = aac_build_sgraw2(cmd, readcmd2,
11660b433447SMahesh Rajashekhara 				dev->scsi_host_ptr->sg_tablesize);
11670b433447SMahesh Rajashekhara 		if (ret < 0)
11680b433447SMahesh Rajashekhara 			return ret;
116985d22bbfSMahesh Rajashekhara 		command = ContainerRawIo2;
117085d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io2) +
117185d22bbfSMahesh Rajashekhara 			((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
117285d22bbfSMahesh Rajashekhara 	} else {
117385d22bbfSMahesh Rajashekhara 		struct aac_raw_io *readcmd;
1174e8f32de5SMark Haverkamp 		readcmd = (struct aac_raw_io *) fib_data(fib);
1175e8f32de5SMark Haverkamp 		readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
1176e8f32de5SMark Haverkamp 		readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1177b836439fSMahesh Rajashekhara 		readcmd->count = cpu_to_le32(count *
1178b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
1179e8f32de5SMark Haverkamp 		readcmd->cid = cpu_to_le16(scmd_id(cmd));
118085d22bbfSMahesh Rajashekhara 		readcmd->flags = cpu_to_le16(RIO_TYPE_READ);
1181e8f32de5SMark Haverkamp 		readcmd->bpTotal = 0;
1182e8f32de5SMark Haverkamp 		readcmd->bpComplete = 0;
11830b433447SMahesh Rajashekhara 		ret = aac_build_sgraw(cmd, &readcmd->sg);
11840b433447SMahesh Rajashekhara 		if (ret < 0)
11850b433447SMahesh Rajashekhara 			return ret;
118685d22bbfSMahesh Rajashekhara 		command = ContainerRawIo;
118785d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io) +
118885d22bbfSMahesh Rajashekhara 			((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw));
118985d22bbfSMahesh Rajashekhara 	}
119085d22bbfSMahesh Rajashekhara 
1191e8f32de5SMark Haverkamp 	BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
1192e8f32de5SMark Haverkamp 	/*
1193e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1194e8f32de5SMark Haverkamp 	 */
119585d22bbfSMahesh Rajashekhara 	return aac_fib_send(command,
1196e8f32de5SMark Haverkamp 			  fib,
1197e8f32de5SMark Haverkamp 			  fibsize,
1198e8f32de5SMark Haverkamp 			  FsaNormal,
1199e8f32de5SMark Haverkamp 			  0, 1,
1200e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1201e8f32de5SMark Haverkamp 			  (void *) cmd);
1202e8f32de5SMark Haverkamp }
1203e8f32de5SMark Haverkamp 
1204e8f32de5SMark Haverkamp static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1205e8f32de5SMark Haverkamp {
1206e8f32de5SMark Haverkamp 	u16 fibsize;
1207e8f32de5SMark Haverkamp 	struct aac_read64 *readcmd;
12080b433447SMahesh Rajashekhara 	long ret;
12090b433447SMahesh Rajashekhara 
1210e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1211e8f32de5SMark Haverkamp 	readcmd = (struct aac_read64 *) fib_data(fib);
1212e8f32de5SMark Haverkamp 	readcmd->command = cpu_to_le32(VM_CtHostRead64);
1213e8f32de5SMark Haverkamp 	readcmd->cid = cpu_to_le16(scmd_id(cmd));
1214e8f32de5SMark Haverkamp 	readcmd->sector_count = cpu_to_le16(count);
1215e8f32de5SMark Haverkamp 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1216e8f32de5SMark Haverkamp 	readcmd->pad   = 0;
1217e8f32de5SMark Haverkamp 	readcmd->flags = 0;
1218e8f32de5SMark Haverkamp 
12190b433447SMahesh Rajashekhara 	ret = aac_build_sg64(cmd, &readcmd->sg);
12200b433447SMahesh Rajashekhara 	if (ret < 0)
12210b433447SMahesh Rajashekhara 		return ret;
1222e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_read64) +
1223e8f32de5SMark Haverkamp 		((le32_to_cpu(readcmd->sg.count) - 1) *
1224e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1225e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1226e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1227e8f32de5SMark Haverkamp 	/*
1228e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1229e8f32de5SMark Haverkamp 	 */
1230e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand64,
1231e8f32de5SMark Haverkamp 			  fib,
1232e8f32de5SMark Haverkamp 			  fibsize,
1233e8f32de5SMark Haverkamp 			  FsaNormal,
1234e8f32de5SMark Haverkamp 			  0, 1,
1235e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1236e8f32de5SMark Haverkamp 			  (void *) cmd);
1237e8f32de5SMark Haverkamp }
1238e8f32de5SMark Haverkamp 
1239e8f32de5SMark Haverkamp static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1240e8f32de5SMark Haverkamp {
1241e8f32de5SMark Haverkamp 	u16 fibsize;
1242e8f32de5SMark Haverkamp 	struct aac_read *readcmd;
1243b836439fSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
12440b433447SMahesh Rajashekhara 	long ret;
12450b433447SMahesh Rajashekhara 
1246e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1247e8f32de5SMark Haverkamp 	readcmd = (struct aac_read *) fib_data(fib);
1248e8f32de5SMark Haverkamp 	readcmd->command = cpu_to_le32(VM_CtBlockRead);
1249f3307f72SChristoph Hellwig 	readcmd->cid = cpu_to_le32(scmd_id(cmd));
1250e8f32de5SMark Haverkamp 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1251b836439fSMahesh Rajashekhara 	readcmd->count = cpu_to_le32(count *
1252b836439fSMahesh Rajashekhara 		dev->fsa_dev[scmd_id(cmd)].block_size);
1253e8f32de5SMark Haverkamp 
12540b433447SMahesh Rajashekhara 	ret = aac_build_sg(cmd, &readcmd->sg);
12550b433447SMahesh Rajashekhara 	if (ret < 0)
12560b433447SMahesh Rajashekhara 		return ret;
1257e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_read) +
1258e8f32de5SMark Haverkamp 			((le32_to_cpu(readcmd->sg.count) - 1) *
1259e8f32de5SMark Haverkamp 			 sizeof (struct sgentry));
1260e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1261e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1262e8f32de5SMark Haverkamp 	/*
1263e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1264e8f32de5SMark Haverkamp 	 */
1265e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand,
1266e8f32de5SMark Haverkamp 			  fib,
1267e8f32de5SMark Haverkamp 			  fibsize,
1268e8f32de5SMark Haverkamp 			  FsaNormal,
1269e8f32de5SMark Haverkamp 			  0, 1,
1270e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1271e8f32de5SMark Haverkamp 			  (void *) cmd);
1272e8f32de5SMark Haverkamp }
1273e8f32de5SMark Haverkamp 
12749d399cc7SSalyzyn, Mark static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1275e8f32de5SMark Haverkamp {
127685d22bbfSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
127785d22bbfSMahesh Rajashekhara 	u16 fibsize, command;
12780b433447SMahesh Rajashekhara 	long ret;
127985d22bbfSMahesh Rajashekhara 
1280e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1281d1ef4da8SRaghava Aditya Renukunta 	if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
1282d1ef4da8SRaghava Aditya Renukunta 		dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) &&
1283d1ef4da8SRaghava Aditya Renukunta 		!dev->sync_mode) {
128485d22bbfSMahesh Rajashekhara 		struct aac_raw_io2 *writecmd2;
128585d22bbfSMahesh Rajashekhara 		writecmd2 = (struct aac_raw_io2 *) fib_data(fib);
128685d22bbfSMahesh Rajashekhara 		memset(writecmd2, 0, sizeof(struct aac_raw_io2));
128785d22bbfSMahesh Rajashekhara 		writecmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff));
128885d22bbfSMahesh Rajashekhara 		writecmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1289b836439fSMahesh Rajashekhara 		writecmd2->byteCount = cpu_to_le32(count *
1290b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
129185d22bbfSMahesh Rajashekhara 		writecmd2->cid = cpu_to_le16(scmd_id(cmd));
129285d22bbfSMahesh Rajashekhara 		writecmd2->flags = (fua && ((aac_cache & 5) != 1) &&
129385d22bbfSMahesh Rajashekhara 						   (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
129485d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO2_IO_TYPE_WRITE|RIO2_IO_SUREWRITE) :
129585d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO2_IO_TYPE_WRITE);
12960b433447SMahesh Rajashekhara 		ret = aac_build_sgraw2(cmd, writecmd2,
12970b433447SMahesh Rajashekhara 				dev->scsi_host_ptr->sg_tablesize);
12980b433447SMahesh Rajashekhara 		if (ret < 0)
12990b433447SMahesh Rajashekhara 			return ret;
130085d22bbfSMahesh Rajashekhara 		command = ContainerRawIo2;
130185d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io2) +
130285d22bbfSMahesh Rajashekhara 			((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
130385d22bbfSMahesh Rajashekhara 	} else {
130485d22bbfSMahesh Rajashekhara 		struct aac_raw_io *writecmd;
1305e8f32de5SMark Haverkamp 		writecmd = (struct aac_raw_io *) fib_data(fib);
1306e8f32de5SMark Haverkamp 		writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
1307e8f32de5SMark Haverkamp 		writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1308b836439fSMahesh Rajashekhara 		writecmd->count = cpu_to_le32(count *
1309b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
1310e8f32de5SMark Haverkamp 		writecmd->cid = cpu_to_le16(scmd_id(cmd));
131195e852e1SSalyzyn, Mark 		writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
131295e852e1SSalyzyn, Mark 						   (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
131385d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO_TYPE_WRITE|RIO_SUREWRITE) :
131485d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO_TYPE_WRITE);
1315e8f32de5SMark Haverkamp 		writecmd->bpTotal = 0;
1316e8f32de5SMark Haverkamp 		writecmd->bpComplete = 0;
13170b433447SMahesh Rajashekhara 		ret = aac_build_sgraw(cmd, &writecmd->sg);
13180b433447SMahesh Rajashekhara 		if (ret < 0)
13190b433447SMahesh Rajashekhara 			return ret;
132085d22bbfSMahesh Rajashekhara 		command = ContainerRawIo;
132185d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io) +
132285d22bbfSMahesh Rajashekhara 			((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw));
132385d22bbfSMahesh Rajashekhara 	}
132485d22bbfSMahesh Rajashekhara 
1325e8f32de5SMark Haverkamp 	BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
1326e8f32de5SMark Haverkamp 	/*
1327e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1328e8f32de5SMark Haverkamp 	 */
132985d22bbfSMahesh Rajashekhara 	return aac_fib_send(command,
1330e8f32de5SMark Haverkamp 			  fib,
1331e8f32de5SMark Haverkamp 			  fibsize,
1332e8f32de5SMark Haverkamp 			  FsaNormal,
1333e8f32de5SMark Haverkamp 			  0, 1,
1334e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1335e8f32de5SMark Haverkamp 			  (void *) cmd);
1336e8f32de5SMark Haverkamp }
1337e8f32de5SMark Haverkamp 
13389d399cc7SSalyzyn, Mark static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1339e8f32de5SMark Haverkamp {
1340e8f32de5SMark Haverkamp 	u16 fibsize;
1341e8f32de5SMark Haverkamp 	struct aac_write64 *writecmd;
13420b433447SMahesh Rajashekhara 	long ret;
13430b433447SMahesh Rajashekhara 
1344e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1345e8f32de5SMark Haverkamp 	writecmd = (struct aac_write64 *) fib_data(fib);
1346e8f32de5SMark Haverkamp 	writecmd->command = cpu_to_le32(VM_CtHostWrite64);
1347e8f32de5SMark Haverkamp 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
1348e8f32de5SMark Haverkamp 	writecmd->sector_count = cpu_to_le16(count);
1349e8f32de5SMark Haverkamp 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1350e8f32de5SMark Haverkamp 	writecmd->pad	= 0;
1351e8f32de5SMark Haverkamp 	writecmd->flags	= 0;
1352e8f32de5SMark Haverkamp 
13530b433447SMahesh Rajashekhara 	ret = aac_build_sg64(cmd, &writecmd->sg);
13540b433447SMahesh Rajashekhara 	if (ret < 0)
13550b433447SMahesh Rajashekhara 		return ret;
1356e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_write64) +
1357e8f32de5SMark Haverkamp 		((le32_to_cpu(writecmd->sg.count) - 1) *
1358e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1359e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1360e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1361e8f32de5SMark Haverkamp 	/*
1362e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1363e8f32de5SMark Haverkamp 	 */
1364e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand64,
1365e8f32de5SMark Haverkamp 			  fib,
1366e8f32de5SMark Haverkamp 			  fibsize,
1367e8f32de5SMark Haverkamp 			  FsaNormal,
1368e8f32de5SMark Haverkamp 			  0, 1,
1369e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1370e8f32de5SMark Haverkamp 			  (void *) cmd);
1371e8f32de5SMark Haverkamp }
1372e8f32de5SMark Haverkamp 
13739d399cc7SSalyzyn, Mark static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1374e8f32de5SMark Haverkamp {
1375e8f32de5SMark Haverkamp 	u16 fibsize;
1376e8f32de5SMark Haverkamp 	struct aac_write *writecmd;
1377b836439fSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
13780b433447SMahesh Rajashekhara 	long ret;
13790b433447SMahesh Rajashekhara 
1380e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1381e8f32de5SMark Haverkamp 	writecmd = (struct aac_write *) fib_data(fib);
1382e8f32de5SMark Haverkamp 	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
1383f3307f72SChristoph Hellwig 	writecmd->cid = cpu_to_le32(scmd_id(cmd));
1384e8f32de5SMark Haverkamp 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1385b836439fSMahesh Rajashekhara 	writecmd->count = cpu_to_le32(count *
1386b836439fSMahesh Rajashekhara 		dev->fsa_dev[scmd_id(cmd)].block_size);
1387e8f32de5SMark Haverkamp 	writecmd->sg.count = cpu_to_le32(1);
1388e8f32de5SMark Haverkamp 	/* ->stable is not used - it did mean which type of write */
1389e8f32de5SMark Haverkamp 
13900b433447SMahesh Rajashekhara 	ret = aac_build_sg(cmd, &writecmd->sg);
13910b433447SMahesh Rajashekhara 	if (ret < 0)
13920b433447SMahesh Rajashekhara 		return ret;
1393e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_write) +
1394e8f32de5SMark Haverkamp 		((le32_to_cpu(writecmd->sg.count) - 1) *
1395e8f32de5SMark Haverkamp 		 sizeof (struct sgentry));
1396e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1397e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1398e8f32de5SMark Haverkamp 	/*
1399e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1400e8f32de5SMark Haverkamp 	 */
1401e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand,
1402e8f32de5SMark Haverkamp 			  fib,
1403e8f32de5SMark Haverkamp 			  fibsize,
1404e8f32de5SMark Haverkamp 			  FsaNormal,
1405e8f32de5SMark Haverkamp 			  0, 1,
1406e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1407e8f32de5SMark Haverkamp 			  (void *) cmd);
1408e8f32de5SMark Haverkamp }
1409e8f32de5SMark Haverkamp 
1410e8f32de5SMark Haverkamp static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd)
1411e8f32de5SMark Haverkamp {
1412e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd;
1413e8f32de5SMark Haverkamp 	u32 flag;
1414e8f32de5SMark Haverkamp 	u32 timeout;
1415e8f32de5SMark Haverkamp 
1416e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1417e8f32de5SMark Haverkamp 	switch(cmd->sc_data_direction){
1418e8f32de5SMark Haverkamp 	case DMA_TO_DEVICE:
1419e8f32de5SMark Haverkamp 		flag = SRB_DataOut;
1420e8f32de5SMark Haverkamp 		break;
1421e8f32de5SMark Haverkamp 	case DMA_BIDIRECTIONAL:
1422e8f32de5SMark Haverkamp 		flag = SRB_DataIn | SRB_DataOut;
1423e8f32de5SMark Haverkamp 		break;
1424e8f32de5SMark Haverkamp 	case DMA_FROM_DEVICE:
1425e8f32de5SMark Haverkamp 		flag = SRB_DataIn;
1426e8f32de5SMark Haverkamp 		break;
1427e8f32de5SMark Haverkamp 	case DMA_NONE:
1428e8f32de5SMark Haverkamp 	default:	/* shuts up some versions of gcc */
1429e8f32de5SMark Haverkamp 		flag = SRB_NoDataXfer;
1430e8f32de5SMark Haverkamp 		break;
1431e8f32de5SMark Haverkamp 	}
1432e8f32de5SMark Haverkamp 
1433e8f32de5SMark Haverkamp 	srbcmd = (struct aac_srb*) fib_data(fib);
1434e8f32de5SMark Haverkamp 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
1435e8f32de5SMark Haverkamp 	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd)));
1436e8f32de5SMark Haverkamp 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
1437e8f32de5SMark Haverkamp 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
1438e8f32de5SMark Haverkamp 	srbcmd->flags    = cpu_to_le32(flag);
1439242f9dcbSJens Axboe 	timeout = cmd->request->timeout/HZ;
1440e8f32de5SMark Haverkamp 	if (timeout == 0)
1441e8f32de5SMark Haverkamp 		timeout = 1;
1442e8f32de5SMark Haverkamp 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
1443e8f32de5SMark Haverkamp 	srbcmd->retry_limit = 0; /* Obsolete parameter */
1444e8f32de5SMark Haverkamp 	srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len);
1445e8f32de5SMark Haverkamp 	return srbcmd;
1446e8f32de5SMark Haverkamp }
1447e8f32de5SMark Haverkamp 
1448e8f32de5SMark Haverkamp static void aac_srb_callback(void *context, struct fib * fibptr);
1449e8f32de5SMark Haverkamp 
1450e8f32de5SMark Haverkamp static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
1451e8f32de5SMark Haverkamp {
1452e8f32de5SMark Haverkamp 	u16 fibsize;
1453e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
14540b433447SMahesh Rajashekhara 	long ret;
1455e8f32de5SMark Haverkamp 
14560b433447SMahesh Rajashekhara 	ret = aac_build_sg64(cmd, (struct sgmap64 *) &srbcmd->sg);
14570b433447SMahesh Rajashekhara 	if (ret < 0)
14580b433447SMahesh Rajashekhara 		return ret;
1459727eead6SFUJITA Tomonori 	srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
1460e8f32de5SMark Haverkamp 
1461e8f32de5SMark Haverkamp 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1462e8f32de5SMark Haverkamp 	memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
1463e8f32de5SMark Haverkamp 	/*
1464e8f32de5SMark Haverkamp 	 *	Build Scatter/Gather list
1465e8f32de5SMark Haverkamp 	 */
1466e8f32de5SMark Haverkamp 	fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
1467e8f32de5SMark Haverkamp 		((le32_to_cpu(srbcmd->sg.count) & 0xff) *
1468e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1469e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1470e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1471e8f32de5SMark Haverkamp 
1472e8f32de5SMark Haverkamp 	/*
1473e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1474e8f32de5SMark Haverkamp 	 */
1475e8f32de5SMark Haverkamp 	return aac_fib_send(ScsiPortCommand64, fib,
1476e8f32de5SMark Haverkamp 				fibsize, FsaNormal, 0, 1,
1477e8f32de5SMark Haverkamp 				  (fib_callback) aac_srb_callback,
1478e8f32de5SMark Haverkamp 				  (void *) cmd);
1479e8f32de5SMark Haverkamp }
1480e8f32de5SMark Haverkamp 
1481e8f32de5SMark Haverkamp static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
1482e8f32de5SMark Haverkamp {
1483e8f32de5SMark Haverkamp 	u16 fibsize;
1484e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
14850b433447SMahesh Rajashekhara 	long ret;
1486e8f32de5SMark Haverkamp 
14870b433447SMahesh Rajashekhara 	ret = aac_build_sg(cmd, (struct sgmap *)&srbcmd->sg);
14880b433447SMahesh Rajashekhara 	if (ret < 0)
14890b433447SMahesh Rajashekhara 		return ret;
1490727eead6SFUJITA Tomonori 	srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
1491e8f32de5SMark Haverkamp 
1492e8f32de5SMark Haverkamp 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1493e8f32de5SMark Haverkamp 	memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
1494e8f32de5SMark Haverkamp 	/*
1495e8f32de5SMark Haverkamp 	 *	Build Scatter/Gather list
1496e8f32de5SMark Haverkamp 	 */
1497e8f32de5SMark Haverkamp 	fibsize = sizeof (struct aac_srb) +
1498e8f32de5SMark Haverkamp 		(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
1499e8f32de5SMark Haverkamp 		 sizeof (struct sgentry));
1500e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1501e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1502e8f32de5SMark Haverkamp 
1503e8f32de5SMark Haverkamp 	/*
1504e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1505e8f32de5SMark Haverkamp 	 */
1506e8f32de5SMark Haverkamp 	return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1,
1507e8f32de5SMark Haverkamp 				  (fib_callback) aac_srb_callback, (void *) cmd);
1508e8f32de5SMark Haverkamp }
1509e8f32de5SMark Haverkamp 
151094cf6ba1SSalyzyn, Mark static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
151194cf6ba1SSalyzyn, Mark {
1512d8e96507SLeubner, Achim 	if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac &&
151394cf6ba1SSalyzyn, Mark 	    (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
151494cf6ba1SSalyzyn, Mark 		return FAILED;
151594cf6ba1SSalyzyn, Mark 	return aac_scsi_32(fib, cmd);
151694cf6ba1SSalyzyn, Mark }
151794cf6ba1SSalyzyn, Mark 
1518c83b11e3SRaghava Aditya Renukunta /**
1519c83b11e3SRaghava Aditya Renukunta  *	aac_update hba_map()-	update current hba map with data from FW
1520c83b11e3SRaghava Aditya Renukunta  *	@dev:	aac_dev structure
1521c83b11e3SRaghava Aditya Renukunta  *	@phys_luns: FW information from report phys luns
1522c83b11e3SRaghava Aditya Renukunta  *
1523c83b11e3SRaghava Aditya Renukunta  *	Update our hba map with the information gathered from the FW
1524c83b11e3SRaghava Aditya Renukunta  */
1525c83b11e3SRaghava Aditya Renukunta void aac_update_hba_map(struct aac_dev *dev,
1526c83b11e3SRaghava Aditya Renukunta 		struct aac_ciss_phys_luns_resp *phys_luns)
1527c83b11e3SRaghava Aditya Renukunta {
1528c83b11e3SRaghava Aditya Renukunta 	/* ok and extended reporting */
1529c83b11e3SRaghava Aditya Renukunta 	u32 lun_count, nexus;
1530c83b11e3SRaghava Aditya Renukunta 	u32 i, bus, target;
1531c83b11e3SRaghava Aditya Renukunta 	u8 expose_flag, attribs;
1532c83b11e3SRaghava Aditya Renukunta 	u8 devtype;
1533c83b11e3SRaghava Aditya Renukunta 
1534c83b11e3SRaghava Aditya Renukunta 	lun_count = ((phys_luns->list_length[0] << 24)
1535c83b11e3SRaghava Aditya Renukunta 			+ (phys_luns->list_length[1] << 16)
1536c83b11e3SRaghava Aditya Renukunta 			+ (phys_luns->list_length[2] << 8)
1537c83b11e3SRaghava Aditya Renukunta 			+ (phys_luns->list_length[3])) / 24;
1538c83b11e3SRaghava Aditya Renukunta 
1539c83b11e3SRaghava Aditya Renukunta 	for (i = 0; i < lun_count; ++i) {
1540c83b11e3SRaghava Aditya Renukunta 
1541c83b11e3SRaghava Aditya Renukunta 		bus = phys_luns->lun[i].level2[1] & 0x3f;
1542c83b11e3SRaghava Aditya Renukunta 		target = phys_luns->lun[i].level2[0];
1543c83b11e3SRaghava Aditya Renukunta 		expose_flag = phys_luns->lun[i].bus >> 6;
1544c83b11e3SRaghava Aditya Renukunta 		attribs = phys_luns->lun[i].node_ident[9];
1545c83b11e3SRaghava Aditya Renukunta 		nexus = *((u32 *) &phys_luns->lun[i].node_ident[12]);
1546c83b11e3SRaghava Aditya Renukunta 
1547c83b11e3SRaghava Aditya Renukunta 		if (bus >= AAC_MAX_BUSES || target >= AAC_MAX_TARGETS)
1548c83b11e3SRaghava Aditya Renukunta 			continue;
1549c83b11e3SRaghava Aditya Renukunta 
1550c83b11e3SRaghava Aditya Renukunta 		dev->hba_map[bus][target].expose = expose_flag;
1551c83b11e3SRaghava Aditya Renukunta 
1552c83b11e3SRaghava Aditya Renukunta 		if (expose_flag != 0) {
1553c83b11e3SRaghava Aditya Renukunta 			devtype = AAC_DEVTYPE_RAID_MEMBER;
1554c83b11e3SRaghava Aditya Renukunta 			goto update_devtype;
1555c83b11e3SRaghava Aditya Renukunta 		}
1556c83b11e3SRaghava Aditya Renukunta 
1557c83b11e3SRaghava Aditya Renukunta 		if (nexus != 0 && (attribs & 8)) {
1558c83b11e3SRaghava Aditya Renukunta 			devtype = AAC_DEVTYPE_NATIVE_RAW;
1559c83b11e3SRaghava Aditya Renukunta 			dev->hba_map[bus][target].rmw_nexus =
1560c83b11e3SRaghava Aditya Renukunta 					nexus;
1561c83b11e3SRaghava Aditya Renukunta 		} else
1562c83b11e3SRaghava Aditya Renukunta 			devtype = AAC_DEVTYPE_ARC_RAW;
1563c83b11e3SRaghava Aditya Renukunta 
1564c83b11e3SRaghava Aditya Renukunta 		if (devtype != AAC_DEVTYPE_NATIVE_RAW)
1565c83b11e3SRaghava Aditya Renukunta 			goto update_devtype;
1566c83b11e3SRaghava Aditya Renukunta 
1567c83b11e3SRaghava Aditya Renukunta update_devtype:
1568c83b11e3SRaghava Aditya Renukunta 		dev->hba_map[bus][target].devtype = devtype;
1569c83b11e3SRaghava Aditya Renukunta 	}
1570c83b11e3SRaghava Aditya Renukunta }
1571c83b11e3SRaghava Aditya Renukunta 
1572c83b11e3SRaghava Aditya Renukunta /**
1573c83b11e3SRaghava Aditya Renukunta  *	aac_report_phys_luns()	Process topology change
1574c83b11e3SRaghava Aditya Renukunta  *	@dev:		aac_dev structure
1575c83b11e3SRaghava Aditya Renukunta  *	@fibptr:	fib pointer
1576c83b11e3SRaghava Aditya Renukunta  *
1577c83b11e3SRaghava Aditya Renukunta  *	Execute a CISS REPORT PHYS LUNS and process the results into
1578c83b11e3SRaghava Aditya Renukunta  *	the current hba_map.
1579c83b11e3SRaghava Aditya Renukunta  */
1580c83b11e3SRaghava Aditya Renukunta int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr)
1581c83b11e3SRaghava Aditya Renukunta {
1582c83b11e3SRaghava Aditya Renukunta 	int fibsize, datasize;
1583c83b11e3SRaghava Aditya Renukunta 	struct aac_ciss_phys_luns_resp *phys_luns;
1584c83b11e3SRaghava Aditya Renukunta 	struct aac_srb *srbcmd;
1585c83b11e3SRaghava Aditya Renukunta 	struct sgmap64 *sg64;
1586c83b11e3SRaghava Aditya Renukunta 	dma_addr_t addr;
1587c83b11e3SRaghava Aditya Renukunta 	u32 vbus, vid;
1588c83b11e3SRaghava Aditya Renukunta 	u32 rcode = 0;
1589c83b11e3SRaghava Aditya Renukunta 
1590c83b11e3SRaghava Aditya Renukunta 	/* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
1591c83b11e3SRaghava Aditya Renukunta 	fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry)
1592c83b11e3SRaghava Aditya Renukunta 			+ sizeof(struct sgentry64);
1593c83b11e3SRaghava Aditya Renukunta 	datasize = sizeof(struct aac_ciss_phys_luns_resp)
1594c83b11e3SRaghava Aditya Renukunta 			+ (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun);
1595c83b11e3SRaghava Aditya Renukunta 
1596c83b11e3SRaghava Aditya Renukunta 	phys_luns = (struct aac_ciss_phys_luns_resp *) pci_alloc_consistent(
1597c83b11e3SRaghava Aditya Renukunta 			dev->pdev, datasize, &addr);
1598c83b11e3SRaghava Aditya Renukunta 
1599c83b11e3SRaghava Aditya Renukunta 	if (phys_luns == NULL) {
1600c83b11e3SRaghava Aditya Renukunta 		rcode = -ENOMEM;
1601c83b11e3SRaghava Aditya Renukunta 		goto err_out;
1602c83b11e3SRaghava Aditya Renukunta 	}
1603c83b11e3SRaghava Aditya Renukunta 
1604c83b11e3SRaghava Aditya Renukunta 	vbus = (u32) le16_to_cpu(
1605c83b11e3SRaghava Aditya Renukunta 			dev->supplement_adapter_info.VirtDeviceBus);
1606c83b11e3SRaghava Aditya Renukunta 	vid = (u32) le16_to_cpu(
1607c83b11e3SRaghava Aditya Renukunta 			dev->supplement_adapter_info.VirtDeviceTarget);
1608c83b11e3SRaghava Aditya Renukunta 
1609c83b11e3SRaghava Aditya Renukunta 	aac_fib_init(fibptr);
1610c83b11e3SRaghava Aditya Renukunta 
1611c83b11e3SRaghava Aditya Renukunta 	srbcmd = (struct aac_srb *) fib_data(fibptr);
1612c83b11e3SRaghava Aditya Renukunta 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
1613c83b11e3SRaghava Aditya Renukunta 	srbcmd->channel = cpu_to_le32(vbus);
1614c83b11e3SRaghava Aditya Renukunta 	srbcmd->id = cpu_to_le32(vid);
1615c83b11e3SRaghava Aditya Renukunta 	srbcmd->lun = 0;
1616c83b11e3SRaghava Aditya Renukunta 	srbcmd->flags = cpu_to_le32(SRB_DataIn);
1617c83b11e3SRaghava Aditya Renukunta 	srbcmd->timeout = cpu_to_le32(10);
1618c83b11e3SRaghava Aditya Renukunta 	srbcmd->retry_limit = 0;
1619c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb_size = cpu_to_le32(12);
1620c83b11e3SRaghava Aditya Renukunta 	srbcmd->count = cpu_to_le32(datasize);
1621c83b11e3SRaghava Aditya Renukunta 
1622c83b11e3SRaghava Aditya Renukunta 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1623c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS;
1624c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[1] = 2; /* extended reporting */
1625c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[8] = (u8)(datasize >> 8);
1626c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[9] = (u8)(datasize);
1627c83b11e3SRaghava Aditya Renukunta 
1628c83b11e3SRaghava Aditya Renukunta 	sg64 = (struct sgmap64 *) &srbcmd->sg;
1629c83b11e3SRaghava Aditya Renukunta 	sg64->count = cpu_to_le32(1);
1630c83b11e3SRaghava Aditya Renukunta 	sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr));
1631c83b11e3SRaghava Aditya Renukunta 	sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr));
1632c83b11e3SRaghava Aditya Renukunta 	sg64->sg[0].count = cpu_to_le32(datasize);
1633c83b11e3SRaghava Aditya Renukunta 
1634c83b11e3SRaghava Aditya Renukunta 	rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize,
1635c83b11e3SRaghava Aditya Renukunta 			FsaNormal, 1, 1, NULL, NULL);
1636c83b11e3SRaghava Aditya Renukunta 
1637c83b11e3SRaghava Aditya Renukunta 	/* analyse data */
1638c83b11e3SRaghava Aditya Renukunta 	if (rcode >= 0 && phys_luns->resp_flag == 2) {
1639c83b11e3SRaghava Aditya Renukunta 		/* ok and extended reporting */
1640c83b11e3SRaghava Aditya Renukunta 		aac_update_hba_map(dev, phys_luns);
1641c83b11e3SRaghava Aditya Renukunta 	}
1642c83b11e3SRaghava Aditya Renukunta 
1643c83b11e3SRaghava Aditya Renukunta 	pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr);
1644c83b11e3SRaghava Aditya Renukunta err_out:
1645c83b11e3SRaghava Aditya Renukunta 	return rcode;
1646c83b11e3SRaghava Aditya Renukunta }
1647c83b11e3SRaghava Aditya Renukunta 
16481da177e4SLinus Torvalds int aac_get_adapter_info(struct aac_dev* dev)
16491da177e4SLinus Torvalds {
16501da177e4SLinus Torvalds 	struct fib* fibptr;
16511da177e4SLinus Torvalds 	int rcode;
1652c83b11e3SRaghava Aditya Renukunta 	u32 tmp, bus, target;
16537c00ffa3SMark Haverkamp  	struct aac_adapter_info *info;
165484971738SMark Haverkamp 	struct aac_bus_info *command;
165584971738SMark Haverkamp 	struct aac_bus_info_response *bus_info;
16567c00ffa3SMark Haverkamp  
1657bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
16581da177e4SLinus Torvalds 		return -ENOMEM;
16591da177e4SLinus Torvalds 
1660bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
16611da177e4SLinus Torvalds 	info = (struct aac_adapter_info *) fib_data(fibptr);
16627c00ffa3SMark Haverkamp  	memset(info,0,sizeof(*info));
16631da177e4SLinus Torvalds 
1664bfb35aa8SMark Haverkamp 	rcode = aac_fib_send(RequestAdapterInfo,
16651da177e4SLinus Torvalds 			 fibptr,
16667c00ffa3SMark Haverkamp  			 sizeof(*info),
16671da177e4SLinus Torvalds 			 FsaNormal,
16689203344cSMark Haverkamp 			 -1, 1, /* First `interrupt' command uses special wait */
16691da177e4SLinus Torvalds 			 NULL,
16701da177e4SLinus Torvalds 			 NULL);
16711da177e4SLinus Torvalds 
16727c00ffa3SMark Haverkamp  	if (rcode < 0) {
1673cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		/* FIB should be freed only after
1674cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		 * getting the response from the F/W */
1675cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		if (rcode != -ERESTARTSYS) {
1676bfb35aa8SMark Haverkamp 			aac_fib_complete(fibptr);
1677bfb35aa8SMark Haverkamp 			aac_fib_free(fibptr);
1678cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		}
16797c00ffa3SMark Haverkamp  		return rcode;
16807c00ffa3SMark Haverkamp  	}
16817c00ffa3SMark Haverkamp  	memcpy(&dev->adapter_info, info, sizeof(*info));
16827c00ffa3SMark Haverkamp  
1683c83b11e3SRaghava Aditya Renukunta 	dev->supplement_adapter_info.VirtDeviceBus = 0xffff;
16847c00ffa3SMark Haverkamp  	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
168506a43d17SSalyzyn, Mark 		struct aac_supplement_adapter_info * sinfo;
16867c00ffa3SMark Haverkamp  
1687bfb35aa8SMark Haverkamp 		aac_fib_init(fibptr);
16887c00ffa3SMark Haverkamp  
168906a43d17SSalyzyn, Mark 		sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
16907c00ffa3SMark Haverkamp  
169106a43d17SSalyzyn, Mark 		memset(sinfo,0,sizeof(*sinfo));
16927c00ffa3SMark Haverkamp  
1693bfb35aa8SMark Haverkamp 		rcode = aac_fib_send(RequestSupplementAdapterInfo,
16947c00ffa3SMark Haverkamp  				 fibptr,
169506a43d17SSalyzyn, Mark 				 sizeof(*sinfo),
16967c00ffa3SMark Haverkamp  				 FsaNormal,
16977c00ffa3SMark Haverkamp  				 1, 1,
16987c00ffa3SMark Haverkamp  				 NULL,
16997c00ffa3SMark Haverkamp  				 NULL);
17007c00ffa3SMark Haverkamp  
17017c00ffa3SMark Haverkamp  		if (rcode >= 0)
170206a43d17SSalyzyn, Mark 			memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
1703cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		if (rcode == -ERESTARTSYS) {
1704cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			fibptr = aac_fib_alloc(dev);
1705cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			if (!fibptr)
1706cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 				return -ENOMEM;
1707cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		}
1708cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
17097c00ffa3SMark Haverkamp  	}
17101da177e4SLinus Torvalds 
1711c83b11e3SRaghava Aditya Renukunta 	/* reset all previous mapped devices (i.e. for init. after IOP_RESET) */
1712c83b11e3SRaghava Aditya Renukunta 	for (bus = 0; bus < AAC_MAX_BUSES; bus++) {
1713c83b11e3SRaghava Aditya Renukunta 		for (target = 0; target < AAC_MAX_TARGETS; target++)
1714c83b11e3SRaghava Aditya Renukunta 			dev->hba_map[bus][target].devtype = 0;
1715c83b11e3SRaghava Aditya Renukunta 	}
171684971738SMark Haverkamp 
171784971738SMark Haverkamp 	/*
171884971738SMark Haverkamp 	 * GetBusInfo
171984971738SMark Haverkamp 	 */
172084971738SMark Haverkamp 
1721bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
172284971738SMark Haverkamp 
172384971738SMark Haverkamp 	bus_info = (struct aac_bus_info_response *) fib_data(fibptr);
172484971738SMark Haverkamp 
172584971738SMark Haverkamp 	memset(bus_info, 0, sizeof(*bus_info));
172684971738SMark Haverkamp 
172784971738SMark Haverkamp 	command = (struct aac_bus_info *)bus_info;
172884971738SMark Haverkamp 
172984971738SMark Haverkamp 	command->Command = cpu_to_le32(VM_Ioctl);
173084971738SMark Haverkamp 	command->ObjType = cpu_to_le32(FT_DRIVE);
173184971738SMark Haverkamp 	command->MethodId = cpu_to_le32(1);
173284971738SMark Haverkamp 	command->CtlCmd = cpu_to_le32(GetBusInfo);
173384971738SMark Haverkamp 
1734bfb35aa8SMark Haverkamp 	rcode = aac_fib_send(ContainerCommand,
173584971738SMark Haverkamp 			 fibptr,
173684971738SMark Haverkamp 			 sizeof (*bus_info),
173784971738SMark Haverkamp 			 FsaNormal,
173884971738SMark Haverkamp 			 1, 1,
173984971738SMark Haverkamp 			 NULL, NULL);
174084971738SMark Haverkamp 
174194cf6ba1SSalyzyn, Mark 	/* reasoned default */
174294cf6ba1SSalyzyn, Mark 	dev->maximum_num_physicals = 16;
174384971738SMark Haverkamp 	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
174484971738SMark Haverkamp 		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
174584971738SMark Haverkamp 		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
174684971738SMark Haverkamp 	}
174784971738SMark Haverkamp 
1748c83b11e3SRaghava Aditya Renukunta 	if (!dev->sync_mode && dev->sa_firmware &&
1749c83b11e3SRaghava Aditya Renukunta 			dev->supplement_adapter_info.VirtDeviceBus != 0xffff) {
1750c83b11e3SRaghava Aditya Renukunta 		/* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
1751c83b11e3SRaghava Aditya Renukunta 		rcode = aac_report_phys_luns(dev, fibptr);
1752c83b11e3SRaghava Aditya Renukunta 	}
1753c83b11e3SRaghava Aditya Renukunta 
17548c867b25SMark Haverkamp 	if (!dev->in_reset) {
175524f02e1dSSalyzyn, Mark 		char buffer[16];
17561da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
17577c00ffa3SMark Haverkamp  		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
17581da177e4SLinus Torvalds 			dev->name,
17591da177e4SLinus Torvalds 			dev->id,
17601da177e4SLinus Torvalds 			tmp>>24,
17611da177e4SLinus Torvalds 			(tmp>>16)&0xff,
17621da177e4SLinus Torvalds 			tmp&0xff,
17637c00ffa3SMark Haverkamp  			le32_to_cpu(dev->adapter_info.kernelbuild),
17647c00ffa3SMark Haverkamp  			(int)sizeof(dev->supplement_adapter_info.BuildDate),
17657c00ffa3SMark Haverkamp  			dev->supplement_adapter_info.BuildDate);
17661da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.monitorrev);
17671da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
17681da177e4SLinus Torvalds 			dev->name, dev->id,
17691da177e4SLinus Torvalds 			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
17701da177e4SLinus Torvalds 			le32_to_cpu(dev->adapter_info.monitorbuild));
17711da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.biosrev);
17721da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
17731da177e4SLinus Torvalds 			dev->name, dev->id,
17741da177e4SLinus Torvalds 			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
17751da177e4SLinus Torvalds 			le32_to_cpu(dev->adapter_info.biosbuild));
177624f02e1dSSalyzyn, Mark 		buffer[0] = '\0';
1777ee959b00STony Jones 		if (aac_get_serial_number(
177824f02e1dSSalyzyn, Mark 		  shost_to_class(dev->scsi_host_ptr), buffer))
177924f02e1dSSalyzyn, Mark 			printk(KERN_INFO "%s%d: serial %s",
178024f02e1dSSalyzyn, Mark 			  dev->name, dev->id, buffer);
1781a45c863fSSalyzyn, Mark 		if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
1782a45c863fSSalyzyn, Mark 			printk(KERN_INFO "%s%d: TSID %.*s\n",
1783a45c863fSSalyzyn, Mark 			  dev->name, dev->id,
1784a45c863fSSalyzyn, Mark 			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
1785a45c863fSSalyzyn, Mark 			  dev->supplement_adapter_info.VpdInfo.Tsid);
1786a45c863fSSalyzyn, Mark 		}
17872f7ecc55SSalyzyn, Mark 		if (!aac_check_reset || ((aac_check_reset == 1) &&
178829c97684SSalyzyn, Mark 		  (dev->supplement_adapter_info.SupportedOptions2 &
1789a3940da5SSalyzyn, Mark 		  AAC_OPTION_IGNORE_RESET))) {
179029c97684SSalyzyn, Mark 			printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
179129c97684SSalyzyn, Mark 			  dev->name, dev->id);
179229c97684SSalyzyn, Mark 		}
17938c867b25SMark Haverkamp 	}
17941da177e4SLinus Torvalds 
179595e852e1SSalyzyn, Mark 	dev->cache_protected = 0;
1796cb1042f2SSalyzyn, Mark 	dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
1797cb1042f2SSalyzyn, Mark 		AAC_FEATURE_JBOD) != 0);
17981da177e4SLinus Torvalds 	dev->nondasd_support = 0;
17991da177e4SLinus Torvalds 	dev->raid_scsi_mode = 0;
180095e852e1SSalyzyn, Mark 	if(dev->adapter_info.options & AAC_OPT_NONDASD)
18011da177e4SLinus Torvalds 		dev->nondasd_support = 1;
18021da177e4SLinus Torvalds 
18031da177e4SLinus Torvalds 	/*
18041da177e4SLinus Torvalds 	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
18051da177e4SLinus Torvalds 	 * in RAID/SCSI mode, set the flag. For now if in this mode we will
18061da177e4SLinus Torvalds 	 * force nondasd support on. If we decide to allow the non-dasd flag
18071da177e4SLinus Torvalds 	 * additional changes changes will have to be made to support
18081da177e4SLinus Torvalds 	 * RAID/SCSI.  the function aac_scsi_cmd in this module will have to be
18091da177e4SLinus Torvalds 	 * changed to support the new dev->raid_scsi_mode flag instead of
18101da177e4SLinus Torvalds 	 * leaching off of the dev->nondasd_support flag. Also in linit.c the
18111da177e4SLinus Torvalds 	 * function aac_detect will have to be modified where it sets up the
18121da177e4SLinus Torvalds 	 * max number of channels based on the aac->nondasd_support flag only.
18131da177e4SLinus Torvalds 	 */
18141da177e4SLinus Torvalds 	if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
18151da177e4SLinus Torvalds 	    (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
18161da177e4SLinus Torvalds 		dev->nondasd_support = 1;
18171da177e4SLinus Torvalds 		dev->raid_scsi_mode = 1;
18181da177e4SLinus Torvalds 	}
18191da177e4SLinus Torvalds 	if (dev->raid_scsi_mode != 0)
18201da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
18211da177e4SLinus Torvalds 				dev->name, dev->id);
18221da177e4SLinus Torvalds 
182395e852e1SSalyzyn, Mark 	if (nondasd != -1)
18241da177e4SLinus Torvalds 		dev->nondasd_support = (nondasd!=0);
18252f7ecc55SSalyzyn, Mark 	if (dev->nondasd_support && !dev->in_reset)
18261da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
18271da177e4SLinus Torvalds 
1828e930438cSYang Hongyang 	if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32))
1829d8e96507SLeubner, Achim 		dev->needs_dac = 1;
18301da177e4SLinus Torvalds 	dev->dac_support = 0;
1831d8e96507SLeubner, Achim 	if ((sizeof(dma_addr_t) > 4) && dev->needs_dac &&
1832d8e96507SLeubner, Achim 	    (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) {
18332f7ecc55SSalyzyn, Mark 		if (!dev->in_reset)
18342f7ecc55SSalyzyn, Mark 			printk(KERN_INFO "%s%d: 64bit support enabled.\n",
18352f7ecc55SSalyzyn, Mark 				dev->name, dev->id);
18361da177e4SLinus Torvalds 		dev->dac_support = 1;
18371da177e4SLinus Torvalds 	}
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds 	if(dacmode != -1) {
18401da177e4SLinus Torvalds 		dev->dac_support = (dacmode!=0);
18411da177e4SLinus Torvalds 	}
1842d8e96507SLeubner, Achim 
1843d8e96507SLeubner, Achim 	/* avoid problems with AAC_QUIRK_SCSI_32 controllers */
1844d8e96507SLeubner, Achim 	if (dev->dac_support &&	(aac_get_driver_ident(dev->cardtype)->quirks
1845d8e96507SLeubner, Achim 		& AAC_QUIRK_SCSI_32)) {
1846d8e96507SLeubner, Achim 		dev->nondasd_support = 0;
1847d8e96507SLeubner, Achim 		dev->jbod = 0;
1848d8e96507SLeubner, Achim 		expose_physicals = 0;
1849d8e96507SLeubner, Achim 	}
1850d8e96507SLeubner, Achim 
18511da177e4SLinus Torvalds 	if(dev->dac_support != 0) {
18526a35528aSYang Hongyang 		if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) &&
18536a35528aSYang Hongyang 			!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
18542f7ecc55SSalyzyn, Mark 			if (!dev->in_reset)
18551da177e4SLinus Torvalds 				printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
18561da177e4SLinus Torvalds 					dev->name, dev->id);
1857284901a9SYang Hongyang 		} else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) &&
1858284901a9SYang Hongyang 			!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) {
18591da177e4SLinus Torvalds 			printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
18601da177e4SLinus Torvalds 				dev->name, dev->id);
18611da177e4SLinus Torvalds 			dev->dac_support = 0;
18621da177e4SLinus Torvalds 		} else {
18631da177e4SLinus Torvalds 			printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
18641da177e4SLinus Torvalds 				dev->name, dev->id);
18651da177e4SLinus Torvalds 			rcode = -ENOMEM;
18661da177e4SLinus Torvalds 		}
18671da177e4SLinus Torvalds 	}
18687c00ffa3SMark Haverkamp  	/*
1869e8f32de5SMark Haverkamp 	 * Deal with configuring for the individualized limits of each packet
1870e8f32de5SMark Haverkamp 	 * interface.
18717c00ffa3SMark Haverkamp  	 */
1872e8f32de5SMark Haverkamp 	dev->a_ops.adapter_scsi = (dev->dac_support)
187394cf6ba1SSalyzyn, Mark 	  ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
187494cf6ba1SSalyzyn, Mark 				? aac_scsi_32_64
187594cf6ba1SSalyzyn, Mark 				: aac_scsi_64)
1876e8f32de5SMark Haverkamp 				: aac_scsi_32;
1877e8f32de5SMark Haverkamp 	if (dev->raw_io_interface) {
1878e8f32de5SMark Haverkamp 		dev->a_ops.adapter_bounds = (dev->raw_io_64)
1879e8f32de5SMark Haverkamp 					? aac_bounds_64
1880e8f32de5SMark Haverkamp 					: aac_bounds_32;
1881e8f32de5SMark Haverkamp 		dev->a_ops.adapter_read = aac_read_raw_io;
1882e8f32de5SMark Haverkamp 		dev->a_ops.adapter_write = aac_write_raw_io;
1883e8f32de5SMark Haverkamp 	} else {
1884e8f32de5SMark Haverkamp 		dev->a_ops.adapter_bounds = aac_bounds_32;
18857c00ffa3SMark Haverkamp  		dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
18867c00ffa3SMark Haverkamp  			sizeof(struct aac_fibhdr) -
188763a70eeaSMark Haverkamp 			sizeof(struct aac_write) + sizeof(struct sgentry)) /
188863a70eeaSMark Haverkamp 				sizeof(struct sgentry);
18897c00ffa3SMark Haverkamp  		if (dev->dac_support) {
1890e8f32de5SMark Haverkamp 			dev->a_ops.adapter_read = aac_read_block64;
1891e8f32de5SMark Haverkamp 			dev->a_ops.adapter_write = aac_write_block64;
18927c00ffa3SMark Haverkamp  			/*
18937c00ffa3SMark Haverkamp  			 * 38 scatter gather elements
18947c00ffa3SMark Haverkamp  			 */
18957c00ffa3SMark Haverkamp  			dev->scsi_host_ptr->sg_tablesize =
18967c00ffa3SMark Haverkamp  				(dev->max_fib_size -
18977c00ffa3SMark Haverkamp  				sizeof(struct aac_fibhdr) -
18987c00ffa3SMark Haverkamp  				sizeof(struct aac_write64) +
189963a70eeaSMark Haverkamp 				sizeof(struct sgentry64)) /
190063a70eeaSMark Haverkamp 					sizeof(struct sgentry64);
1901e8f32de5SMark Haverkamp 		} else {
1902e8f32de5SMark Haverkamp 			dev->a_ops.adapter_read = aac_read_block;
1903e8f32de5SMark Haverkamp 			dev->a_ops.adapter_write = aac_write_block;
19047c00ffa3SMark Haverkamp  		}
19057c00ffa3SMark Haverkamp  		dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
19067c00ffa3SMark Haverkamp  		if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
19077c00ffa3SMark Haverkamp  			/*
19087c00ffa3SMark Haverkamp  			 * Worst case size that could cause sg overflow when
19097c00ffa3SMark Haverkamp  			 * we break up SG elements that are larger than 64KB.
19107c00ffa3SMark Haverkamp  			 * Would be nice if we could tell the SCSI layer what
19117c00ffa3SMark Haverkamp  			 * the maximum SG element size can be. Worst case is
19127c00ffa3SMark Haverkamp  			 * (sg_tablesize-1) 4KB elements with one 64KB
19137c00ffa3SMark Haverkamp  			 * element.
19147c00ffa3SMark Haverkamp  			 *	32bit -> 468 or 238KB	64bit -> 424 or 212KB
19157c00ffa3SMark Haverkamp  			 */
19167c00ffa3SMark Haverkamp  			dev->scsi_host_ptr->max_sectors =
19177c00ffa3SMark Haverkamp  			  (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
19187c00ffa3SMark Haverkamp  		}
19190e68c003SMark Haverkamp 	}
1920cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
1921cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (rcode != -ERESTARTSYS) {
1922bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
1923bfb35aa8SMark Haverkamp 		aac_fib_free(fibptr);
1924cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	}
19251da177e4SLinus Torvalds 
19261da177e4SLinus Torvalds 	return rcode;
19271da177e4SLinus Torvalds }
19281da177e4SLinus Torvalds 
19291da177e4SLinus Torvalds 
1930e53cb35aSMark Haverkamp static void io_callback(void *context, struct fib * fibptr)
19311da177e4SLinus Torvalds {
19321da177e4SLinus Torvalds 	struct aac_dev *dev;
19331da177e4SLinus Torvalds 	struct aac_read_reply *readreply;
19341da177e4SLinus Torvalds 	struct scsi_cmnd *scsicmd;
19351da177e4SLinus Torvalds 	u32 cid;
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
19381da177e4SLinus Torvalds 
193903d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
194003d44337SMark Haverkamp 		return;
194103d44337SMark Haverkamp 
19421a655040SSalyzyn, Mark 	dev = fibptr->dev;
1943e5718774SMark Haverkamp 	cid = scmd_id(scsicmd);
19441da177e4SLinus Torvalds 
19457a8cf29dSMark Haverkamp 	if (nblank(dprintk(x))) {
19467a8cf29dSMark Haverkamp 		u64 lba;
19477a8cf29dSMark Haverkamp 		switch (scsicmd->cmnd[0]) {
19487a8cf29dSMark Haverkamp 		case WRITE_6:
19497a8cf29dSMark Haverkamp 		case READ_6:
19507a8cf29dSMark Haverkamp 			lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
19517a8cf29dSMark Haverkamp 			    (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
19527a8cf29dSMark Haverkamp 			break;
19537a8cf29dSMark Haverkamp 		case WRITE_16:
19547a8cf29dSMark Haverkamp 		case READ_16:
19557a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 56) |
19567a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[3] << 48) |
19577a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[4] << 40) |
19587a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[5] << 32) |
19597a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[6] << 24) |
19607a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[7] << 16) |
19617a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
19627a8cf29dSMark Haverkamp 			break;
19637a8cf29dSMark Haverkamp 		case WRITE_12:
19647a8cf29dSMark Haverkamp 		case READ_12:
19657a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 24) |
19667a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[3] << 16) |
19677a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
19687a8cf29dSMark Haverkamp 			break;
19697a8cf29dSMark Haverkamp 		default:
19707a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 24) |
19717a8cf29dSMark Haverkamp 			       (scsicmd->cmnd[3] << 16) |
19727a8cf29dSMark Haverkamp 			       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
19737a8cf29dSMark Haverkamp 			break;
19747a8cf29dSMark Haverkamp 		}
19757a8cf29dSMark Haverkamp 		printk(KERN_DEBUG
19767a8cf29dSMark Haverkamp 		  "io_callback[cpu %d]: lba = %llu, t = %ld.\n",
19777a8cf29dSMark Haverkamp 		  smp_processor_id(), (unsigned long long)lba, jiffies);
19787a8cf29dSMark Haverkamp 	}
19791da177e4SLinus Torvalds 
1980125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
19811da177e4SLinus Torvalds 
1982727eead6SFUJITA Tomonori 	scsi_dma_unmap(scsicmd);
1983727eead6SFUJITA Tomonori 
19841da177e4SLinus Torvalds 	readreply = (struct aac_read_reply *)fib_data(fibptr);
1985655d722cSMark Salyzyn 	switch (le32_to_cpu(readreply->status)) {
1986655d722cSMark Salyzyn 	case ST_OK:
1987655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1988655d722cSMark Salyzyn 			SAM_STAT_GOOD;
1989655d722cSMark Salyzyn 		dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
1990655d722cSMark Salyzyn 		break;
1991655d722cSMark Salyzyn 	case ST_NOT_READY:
1992655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1993655d722cSMark Salyzyn 			SAM_STAT_CHECK_CONDITION;
1994655d722cSMark Salyzyn 		set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
1995655d722cSMark Salyzyn 		  SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
1996655d722cSMark Salyzyn 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
1997655d722cSMark Salyzyn 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
1998655d722cSMark Salyzyn 			     SCSI_SENSE_BUFFERSIZE));
1999655d722cSMark Salyzyn 		break;
2000655d722cSMark Salyzyn 	default:
20017c00ffa3SMark Haverkamp  #ifdef AAC_DETAILED_STATUS_INFO
2002e53cb35aSMark Haverkamp 		printk(KERN_WARNING "io_callback: io failed, status = %d\n",
20031da177e4SLinus Torvalds 		  le32_to_cpu(readreply->status));
20047c00ffa3SMark Haverkamp  #endif
2005655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2006655d722cSMark Salyzyn 			SAM_STAT_CHECK_CONDITION;
20078e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
20088e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
20098e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
20101da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
20113ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
20123ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
2013655d722cSMark Salyzyn 		break;
20141da177e4SLinus Torvalds 	}
2015bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
20161da177e4SLinus Torvalds 
20178e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
20181da177e4SLinus Torvalds }
20191da177e4SLinus Torvalds 
20209e7c349cSMark Haverkamp static int aac_read(struct scsi_cmnd * scsicmd)
20211da177e4SLinus Torvalds {
20227a8cf29dSMark Haverkamp 	u64 lba;
20231da177e4SLinus Torvalds 	u32 count;
20241da177e4SLinus Torvalds 	int status;
20251da177e4SLinus Torvalds 	struct aac_dev *dev;
20261da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
2027da3cc679SRajashekhara, Mahesh 	int cid;
20281da177e4SLinus Torvalds 
20291da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
20301da177e4SLinus Torvalds 	/*
20311da177e4SLinus Torvalds 	 *	Get block address and transfer length
20321da177e4SLinus Torvalds 	 */
20337a8cf29dSMark Haverkamp 	switch (scsicmd->cmnd[0]) {
20347a8cf29dSMark Haverkamp 	case READ_6:
20359e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
20361da177e4SLinus Torvalds 
20377a8cf29dSMark Haverkamp 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
20387a8cf29dSMark Haverkamp 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
20391da177e4SLinus Torvalds 		count = scsicmd->cmnd[4];
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 		if (count == 0)
20421da177e4SLinus Torvalds 			count = 256;
20437a8cf29dSMark Haverkamp 		break;
20447a8cf29dSMark Haverkamp 	case READ_16:
20459e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
20467a8cf29dSMark Haverkamp 
20477a8cf29dSMark Haverkamp 		lba =	((u64)scsicmd->cmnd[2] << 56) |
20487a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[3] << 48) |
20497a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[4] << 40) |
20507a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[5] << 32) |
20517a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[6] << 24) |
20527a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
20537a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
20547a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[10] << 24) |
20557a8cf29dSMark Haverkamp 			(scsicmd->cmnd[11] << 16) |
20567a8cf29dSMark Haverkamp 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
20577a8cf29dSMark Haverkamp 		break;
20587a8cf29dSMark Haverkamp 	case READ_12:
20599e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
20607a8cf29dSMark Haverkamp 
20617a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) |
20627a8cf29dSMark Haverkamp 			(scsicmd->cmnd[3] << 16) |
20637a8cf29dSMark Haverkamp 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
20647a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[6] << 24) |
20657a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
20667a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
20677a8cf29dSMark Haverkamp 		break;
20687a8cf29dSMark Haverkamp 	default:
20699e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
20701da177e4SLinus Torvalds 
20717a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) |
20727a8cf29dSMark Haverkamp 			(scsicmd->cmnd[3] << 16) |
20737a8cf29dSMark Haverkamp 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
20741da177e4SLinus Torvalds 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
20757a8cf29dSMark Haverkamp 		break;
20761da177e4SLinus Torvalds 	}
2077da3cc679SRajashekhara, Mahesh 
2078da3cc679SRajashekhara, Mahesh 	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
2079da3cc679SRajashekhara, Mahesh 		cid = scmd_id(scsicmd);
2080da3cc679SRajashekhara, Mahesh 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
2081da3cc679SRajashekhara, Mahesh 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2082da3cc679SRajashekhara, Mahesh 			SAM_STAT_CHECK_CONDITION;
2083da3cc679SRajashekhara, Mahesh 		set_sense(&dev->fsa_dev[cid].sense_data,
2084da3cc679SRajashekhara, Mahesh 			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
2085da3cc679SRajashekhara, Mahesh 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
2086da3cc679SRajashekhara, Mahesh 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2087da3cc679SRajashekhara, Mahesh 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2088da3cc679SRajashekhara, Mahesh 			     SCSI_SENSE_BUFFERSIZE));
2089da3cc679SRajashekhara, Mahesh 		scsicmd->scsi_done(scsicmd);
2090da3cc679SRajashekhara, Mahesh 		return 1;
2091da3cc679SRajashekhara, Mahesh 	}
2092da3cc679SRajashekhara, Mahesh 
20937a8cf29dSMark Haverkamp 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
20947c00ffa3SMark Haverkamp  	  smp_processor_id(), (unsigned long long)lba, jiffies));
2095e8f32de5SMark Haverkamp 	if (aac_adapter_bounds(dev,scsicmd,lba))
20967a8cf29dSMark Haverkamp 		return 0;
20971da177e4SLinus Torvalds 	/*
20981da177e4SLinus Torvalds 	 *	Alocate and initialize a Fib
20991da177e4SLinus Torvalds 	 */
21006bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
21011da177e4SLinus Torvalds 
2102e8f32de5SMark Haverkamp 	status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
21031da177e4SLinus Torvalds 
21041da177e4SLinus Torvalds 	/*
21051da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
21061da177e4SLinus Torvalds 	 */
210777d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
210877d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
21091da177e4SLinus Torvalds 		return 0;
211077d644d4SMark Haverkamp 	}
21111da177e4SLinus Torvalds 
2112bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
21131da177e4SLinus Torvalds 	/*
21141da177e4SLinus Torvalds 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
21151da177e4SLinus Torvalds 	 */
21161da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
21178e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
2118bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2119bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
21201da177e4SLinus Torvalds 	return 0;
21211da177e4SLinus Torvalds }
21221da177e4SLinus Torvalds 
21239e7c349cSMark Haverkamp static int aac_write(struct scsi_cmnd * scsicmd)
21241da177e4SLinus Torvalds {
21257a8cf29dSMark Haverkamp 	u64 lba;
21261da177e4SLinus Torvalds 	u32 count;
21279d399cc7SSalyzyn, Mark 	int fua;
21281da177e4SLinus Torvalds 	int status;
21291da177e4SLinus Torvalds 	struct aac_dev *dev;
21301da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
2131da3cc679SRajashekhara, Mahesh 	int cid;
21321da177e4SLinus Torvalds 
21331da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
21341da177e4SLinus Torvalds 	/*
21351da177e4SLinus Torvalds 	 *	Get block address and transfer length
21361da177e4SLinus Torvalds 	 */
21371da177e4SLinus Torvalds 	if (scsicmd->cmnd[0] == WRITE_6)	/* 6 byte command */
21381da177e4SLinus Torvalds 	{
21391da177e4SLinus Torvalds 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
21401da177e4SLinus Torvalds 		count = scsicmd->cmnd[4];
21411da177e4SLinus Torvalds 		if (count == 0)
21421da177e4SLinus Torvalds 			count = 256;
21439d399cc7SSalyzyn, Mark 		fua = 0;
21447a8cf29dSMark Haverkamp 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
21459e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
21467a8cf29dSMark Haverkamp 
21477a8cf29dSMark Haverkamp 		lba =	((u64)scsicmd->cmnd[2] << 56) |
21487a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[3] << 48) |
21497a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[4] << 40) |
21507a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[5] << 32) |
21517a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[6] << 24) |
21527a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
21537a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
21547a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
21557a8cf29dSMark Haverkamp 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
21569d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
21577a8cf29dSMark Haverkamp 	} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
21589e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
21597a8cf29dSMark Haverkamp 
21607a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
21617a8cf29dSMark Haverkamp 		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
21627a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
21637a8cf29dSMark Haverkamp 		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
21649d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
21651da177e4SLinus Torvalds 	} else {
21669e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
21677a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
21681da177e4SLinus Torvalds 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
21699d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
21701da177e4SLinus Torvalds 	}
2171da3cc679SRajashekhara, Mahesh 
2172da3cc679SRajashekhara, Mahesh 	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
2173da3cc679SRajashekhara, Mahesh 		cid = scmd_id(scsicmd);
2174da3cc679SRajashekhara, Mahesh 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
2175da3cc679SRajashekhara, Mahesh 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2176da3cc679SRajashekhara, Mahesh 			SAM_STAT_CHECK_CONDITION;
2177da3cc679SRajashekhara, Mahesh 		set_sense(&dev->fsa_dev[cid].sense_data,
2178da3cc679SRajashekhara, Mahesh 			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
2179da3cc679SRajashekhara, Mahesh 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
2180da3cc679SRajashekhara, Mahesh 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2181da3cc679SRajashekhara, Mahesh 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2182da3cc679SRajashekhara, Mahesh 			     SCSI_SENSE_BUFFERSIZE));
2183da3cc679SRajashekhara, Mahesh 		scsicmd->scsi_done(scsicmd);
2184da3cc679SRajashekhara, Mahesh 		return 1;
2185da3cc679SRajashekhara, Mahesh 	}
2186da3cc679SRajashekhara, Mahesh 
21877a8cf29dSMark Haverkamp 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
21881da177e4SLinus Torvalds 	  smp_processor_id(), (unsigned long long)lba, jiffies));
2189e8f32de5SMark Haverkamp 	if (aac_adapter_bounds(dev,scsicmd,lba))
21907a8cf29dSMark Haverkamp 		return 0;
21911da177e4SLinus Torvalds 	/*
21921da177e4SLinus Torvalds 	 *	Allocate and initialize a Fib then setup a BlockWrite command
21931da177e4SLinus Torvalds 	 */
21946bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
21951da177e4SLinus Torvalds 
21969d399cc7SSalyzyn, Mark 	status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 	/*
21991da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
22001da177e4SLinus Torvalds 	 */
220177d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
220277d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
22031da177e4SLinus Torvalds 		return 0;
22041da177e4SLinus Torvalds 	}
22051da177e4SLinus Torvalds 
2206bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
22071da177e4SLinus Torvalds 	/*
22081da177e4SLinus Torvalds 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
22091da177e4SLinus Torvalds 	 */
22101da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
22118e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
22121da177e4SLinus Torvalds 
2213bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2214bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
22151da177e4SLinus Torvalds 	return 0;
22161da177e4SLinus Torvalds }
22171da177e4SLinus Torvalds 
22181da177e4SLinus Torvalds static void synchronize_callback(void *context, struct fib *fibptr)
22191da177e4SLinus Torvalds {
22201da177e4SLinus Torvalds 	struct aac_synchronize_reply *synchronizereply;
22211da177e4SLinus Torvalds 	struct scsi_cmnd *cmd;
22221da177e4SLinus Torvalds 
22231da177e4SLinus Torvalds 	cmd = context;
22241da177e4SLinus Torvalds 
222503d44337SMark Haverkamp 	if (!aac_valid_context(cmd, fibptr))
222603d44337SMark Haverkamp 		return;
222703d44337SMark Haverkamp 
22281da177e4SLinus Torvalds 	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
22291da177e4SLinus Torvalds 				smp_processor_id(), jiffies));
22301da177e4SLinus Torvalds 	BUG_ON(fibptr == NULL);
22311da177e4SLinus Torvalds 
22321da177e4SLinus Torvalds 
22331da177e4SLinus Torvalds 	synchronizereply = fib_data(fibptr);
22341da177e4SLinus Torvalds 	if (le32_to_cpu(synchronizereply->status) == CT_OK)
22351da177e4SLinus Torvalds 		cmd->result = DID_OK << 16 |
22361da177e4SLinus Torvalds 			COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
22371da177e4SLinus Torvalds 	else {
22381da177e4SLinus Torvalds 		struct scsi_device *sdev = cmd->device;
22391a655040SSalyzyn, Mark 		struct aac_dev *dev = fibptr->dev;
2240e5718774SMark Haverkamp 		u32 cid = sdev_id(sdev);
22411da177e4SLinus Torvalds 		printk(KERN_WARNING
22421da177e4SLinus Torvalds 		     "synchronize_callback: synchronize failed, status = %d\n",
22431da177e4SLinus Torvalds 		     le32_to_cpu(synchronizereply->status));
22441da177e4SLinus Torvalds 		cmd->result = DID_OK << 16 |
22451da177e4SLinus Torvalds 			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
22468e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
22478e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
22488e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
22491da177e4SLinus Torvalds 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2250b80ca4f7SFUJITA Tomonori 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2251b80ca4f7SFUJITA Tomonori 			     SCSI_SENSE_BUFFERSIZE));
22521da177e4SLinus Torvalds 	}
22531da177e4SLinus Torvalds 
2254bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
2255bfb35aa8SMark Haverkamp 	aac_fib_free(fibptr);
22568e0c5ebdSMark Haverkamp 	cmd->scsi_done(cmd);
22571da177e4SLinus Torvalds }
22581da177e4SLinus Torvalds 
22599e7c349cSMark Haverkamp static int aac_synchronize(struct scsi_cmnd *scsicmd)
22601da177e4SLinus Torvalds {
22611da177e4SLinus Torvalds 	int status;
22621da177e4SLinus Torvalds 	struct fib *cmd_fibcontext;
22631da177e4SLinus Torvalds 	struct aac_synchronize *synchronizecmd;
22641da177e4SLinus Torvalds 	struct scsi_cmnd *cmd;
22651da177e4SLinus Torvalds 	struct scsi_device *sdev = scsicmd->device;
22661da177e4SLinus Torvalds 	int active = 0;
226790ee3466SMark Haverkamp 	struct aac_dev *aac;
2268b90f90d2SSalyzyn, Mark 	u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) |
2269b90f90d2SSalyzyn, Mark 		(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
2270b90f90d2SSalyzyn, Mark 	u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
22711da177e4SLinus Torvalds 	unsigned long flags;
22721da177e4SLinus Torvalds 
22731da177e4SLinus Torvalds 	/*
227477d644d4SMark Haverkamp 	 * Wait for all outstanding queued commands to complete to this
227577d644d4SMark Haverkamp 	 * specific target (block).
22761da177e4SLinus Torvalds 	 */
22771da177e4SLinus Torvalds 	spin_lock_irqsave(&sdev->list_lock, flags);
22781da177e4SLinus Torvalds 	list_for_each_entry(cmd, &sdev->cmd_list, list)
2279b90f90d2SSalyzyn, Mark 		if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
2280b90f90d2SSalyzyn, Mark 			u64 cmnd_lba;
2281b90f90d2SSalyzyn, Mark 			u32 cmnd_count;
2282b90f90d2SSalyzyn, Mark 
2283b90f90d2SSalyzyn, Mark 			if (cmd->cmnd[0] == WRITE_6) {
2284b90f90d2SSalyzyn, Mark 				cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) |
2285b90f90d2SSalyzyn, Mark 					(cmd->cmnd[2] << 8) |
2286b90f90d2SSalyzyn, Mark 					cmd->cmnd[3];
2287b90f90d2SSalyzyn, Mark 				cmnd_count = cmd->cmnd[4];
2288b90f90d2SSalyzyn, Mark 				if (cmnd_count == 0)
2289b90f90d2SSalyzyn, Mark 					cmnd_count = 256;
2290b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_16) {
2291b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 56) |
2292b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[3] << 48) |
2293b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[4] << 40) |
2294b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[5] << 32) |
2295b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[6] << 24) |
2296b90f90d2SSalyzyn, Mark 					(cmd->cmnd[7] << 16) |
2297b90f90d2SSalyzyn, Mark 					(cmd->cmnd[8] << 8) |
2298b90f90d2SSalyzyn, Mark 					cmd->cmnd[9];
2299b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[10] << 24) |
2300b90f90d2SSalyzyn, Mark 					(cmd->cmnd[11] << 16) |
2301b90f90d2SSalyzyn, Mark 					(cmd->cmnd[12] << 8) |
2302b90f90d2SSalyzyn, Mark 					cmd->cmnd[13];
2303b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_12) {
2304b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
2305b90f90d2SSalyzyn, Mark 					(cmd->cmnd[3] << 16) |
2306b90f90d2SSalyzyn, Mark 					(cmd->cmnd[4] << 8) |
2307b90f90d2SSalyzyn, Mark 					cmd->cmnd[5];
2308b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[6] << 24) |
2309b90f90d2SSalyzyn, Mark 					(cmd->cmnd[7] << 16) |
2310b90f90d2SSalyzyn, Mark 					(cmd->cmnd[8] << 8) |
2311b90f90d2SSalyzyn, Mark 					cmd->cmnd[9];
2312b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_10) {
2313b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
2314b90f90d2SSalyzyn, Mark 					(cmd->cmnd[3] << 16) |
2315b90f90d2SSalyzyn, Mark 					(cmd->cmnd[4] << 8) |
2316b90f90d2SSalyzyn, Mark 					cmd->cmnd[5];
2317b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[7] << 8) |
2318b90f90d2SSalyzyn, Mark 					cmd->cmnd[8];
2319b90f90d2SSalyzyn, Mark 			} else
2320b90f90d2SSalyzyn, Mark 				continue;
2321b90f90d2SSalyzyn, Mark 			if (((cmnd_lba + cmnd_count) < lba) ||
2322b90f90d2SSalyzyn, Mark 			  (count && ((lba + count) < cmnd_lba)))
2323b90f90d2SSalyzyn, Mark 				continue;
23241da177e4SLinus Torvalds 			++active;
23251da177e4SLinus Torvalds 			break;
23261da177e4SLinus Torvalds 		}
23271da177e4SLinus Torvalds 
23281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&sdev->list_lock, flags);
23291da177e4SLinus Torvalds 
23301da177e4SLinus Torvalds 	/*
23311da177e4SLinus Torvalds 	 *	Yield the processor (requeue for later)
23321da177e4SLinus Torvalds 	 */
23331da177e4SLinus Torvalds 	if (active)
23341da177e4SLinus Torvalds 		return SCSI_MLQUEUE_DEVICE_BUSY;
23351da177e4SLinus Torvalds 
2336f858317dSSalyzyn, Mark 	aac = (struct aac_dev *)sdev->host->hostdata;
23378c867b25SMark Haverkamp 	if (aac->in_reset)
23388c867b25SMark Haverkamp 		return SCSI_MLQUEUE_HOST_BUSY;
23398c867b25SMark Haverkamp 
23401da177e4SLinus Torvalds 	/*
23417c00ffa3SMark Haverkamp  	 *	Allocate and initialize a Fib
23421da177e4SLinus Torvalds 	 */
234390ee3466SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(aac)))
23441da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
23451da177e4SLinus Torvalds 
2346bfb35aa8SMark Haverkamp 	aac_fib_init(cmd_fibcontext);
23471da177e4SLinus Torvalds 
23481da177e4SLinus Torvalds 	synchronizecmd = fib_data(cmd_fibcontext);
23491da177e4SLinus Torvalds 	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
23501da177e4SLinus Torvalds 	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
23519e7c349cSMark Haverkamp 	synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
23521da177e4SLinus Torvalds 	synchronizecmd->count =
23531da177e4SLinus Torvalds 	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 	/*
23561da177e4SLinus Torvalds 	 *	Now send the Fib to the adapter
23571da177e4SLinus Torvalds 	 */
2358bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
23591da177e4SLinus Torvalds 		  cmd_fibcontext,
23601da177e4SLinus Torvalds 		  sizeof(struct aac_synchronize),
23611da177e4SLinus Torvalds 		  FsaNormal,
23621da177e4SLinus Torvalds 		  0, 1,
23631da177e4SLinus Torvalds 		  (fib_callback)synchronize_callback,
23641da177e4SLinus Torvalds 		  (void *)scsicmd);
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 	/*
23671da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
23681da177e4SLinus Torvalds 	 */
236977d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
237077d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
23711da177e4SLinus Torvalds 		return 0;
237277d644d4SMark Haverkamp 	}
23731da177e4SLinus Torvalds 
23741da177e4SLinus Torvalds 	printk(KERN_WARNING
2375bfb35aa8SMark Haverkamp 		"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
2376bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2377bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
23781da177e4SLinus Torvalds 	return SCSI_MLQUEUE_HOST_BUSY;
23791da177e4SLinus Torvalds }
23801da177e4SLinus Torvalds 
2381655d722cSMark Salyzyn static void aac_start_stop_callback(void *context, struct fib *fibptr)
2382655d722cSMark Salyzyn {
2383655d722cSMark Salyzyn 	struct scsi_cmnd *scsicmd = context;
2384655d722cSMark Salyzyn 
2385655d722cSMark Salyzyn 	if (!aac_valid_context(scsicmd, fibptr))
2386655d722cSMark Salyzyn 		return;
2387655d722cSMark Salyzyn 
2388655d722cSMark Salyzyn 	BUG_ON(fibptr == NULL);
2389655d722cSMark Salyzyn 
2390655d722cSMark Salyzyn 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
2391655d722cSMark Salyzyn 
2392655d722cSMark Salyzyn 	aac_fib_complete(fibptr);
2393655d722cSMark Salyzyn 	aac_fib_free(fibptr);
2394655d722cSMark Salyzyn 	scsicmd->scsi_done(scsicmd);
2395655d722cSMark Salyzyn }
2396655d722cSMark Salyzyn 
2397655d722cSMark Salyzyn static int aac_start_stop(struct scsi_cmnd *scsicmd)
2398655d722cSMark Salyzyn {
2399655d722cSMark Salyzyn 	int status;
2400655d722cSMark Salyzyn 	struct fib *cmd_fibcontext;
2401655d722cSMark Salyzyn 	struct aac_power_management *pmcmd;
2402655d722cSMark Salyzyn 	struct scsi_device *sdev = scsicmd->device;
2403655d722cSMark Salyzyn 	struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
2404655d722cSMark Salyzyn 
2405655d722cSMark Salyzyn 	if (!(aac->supplement_adapter_info.SupportedOptions2 &
2406655d722cSMark Salyzyn 	      AAC_OPTION_POWER_MANAGEMENT)) {
2407655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2408655d722cSMark Salyzyn 				  SAM_STAT_GOOD;
2409655d722cSMark Salyzyn 		scsicmd->scsi_done(scsicmd);
2410655d722cSMark Salyzyn 		return 0;
2411655d722cSMark Salyzyn 	}
2412655d722cSMark Salyzyn 
2413655d722cSMark Salyzyn 	if (aac->in_reset)
2414655d722cSMark Salyzyn 		return SCSI_MLQUEUE_HOST_BUSY;
2415655d722cSMark Salyzyn 
2416655d722cSMark Salyzyn 	/*
2417655d722cSMark Salyzyn 	 *	Allocate and initialize a Fib
2418655d722cSMark Salyzyn 	 */
24196bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd);
2420655d722cSMark Salyzyn 
2421655d722cSMark Salyzyn 	aac_fib_init(cmd_fibcontext);
2422655d722cSMark Salyzyn 
2423655d722cSMark Salyzyn 	pmcmd = fib_data(cmd_fibcontext);
2424655d722cSMark Salyzyn 	pmcmd->command = cpu_to_le32(VM_ContainerConfig);
2425655d722cSMark Salyzyn 	pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
2426655d722cSMark Salyzyn 	/* Eject bit ignored, not relevant */
2427655d722cSMark Salyzyn 	pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
2428655d722cSMark Salyzyn 		cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
2429655d722cSMark Salyzyn 	pmcmd->cid = cpu_to_le32(sdev_id(sdev));
2430655d722cSMark Salyzyn 	pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
2431655d722cSMark Salyzyn 		cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
2432655d722cSMark Salyzyn 
2433655d722cSMark Salyzyn 	/*
2434655d722cSMark Salyzyn 	 *	Now send the Fib to the adapter
2435655d722cSMark Salyzyn 	 */
2436655d722cSMark Salyzyn 	status = aac_fib_send(ContainerCommand,
2437655d722cSMark Salyzyn 		  cmd_fibcontext,
2438655d722cSMark Salyzyn 		  sizeof(struct aac_power_management),
2439655d722cSMark Salyzyn 		  FsaNormal,
2440655d722cSMark Salyzyn 		  0, 1,
2441655d722cSMark Salyzyn 		  (fib_callback)aac_start_stop_callback,
2442655d722cSMark Salyzyn 		  (void *)scsicmd);
2443655d722cSMark Salyzyn 
2444655d722cSMark Salyzyn 	/*
2445655d722cSMark Salyzyn 	 *	Check that the command queued to the controller
2446655d722cSMark Salyzyn 	 */
2447655d722cSMark Salyzyn 	if (status == -EINPROGRESS) {
2448655d722cSMark Salyzyn 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2449655d722cSMark Salyzyn 		return 0;
2450655d722cSMark Salyzyn 	}
2451655d722cSMark Salyzyn 
2452655d722cSMark Salyzyn 	aac_fib_complete(cmd_fibcontext);
2453655d722cSMark Salyzyn 	aac_fib_free(cmd_fibcontext);
2454655d722cSMark Salyzyn 	return SCSI_MLQUEUE_HOST_BUSY;
2455655d722cSMark Salyzyn }
2456655d722cSMark Salyzyn 
24571da177e4SLinus Torvalds /**
24581da177e4SLinus Torvalds  *	aac_scsi_cmd()		-	Process SCSI command
24591da177e4SLinus Torvalds  *	@scsicmd:		SCSI command block
24601da177e4SLinus Torvalds  *
24611da177e4SLinus Torvalds  *	Emulate a SCSI command and queue the required request for the
24621da177e4SLinus Torvalds  *	aacraid firmware.
24631da177e4SLinus Torvalds  */
24641da177e4SLinus Torvalds 
24651da177e4SLinus Torvalds int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
24661da177e4SLinus Torvalds {
24671a655040SSalyzyn, Mark 	u32 cid;
24681da177e4SLinus Torvalds 	struct Scsi_Host *host = scsicmd->device->host;
24691da177e4SLinus Torvalds 	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
24701da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
24711da177e4SLinus Torvalds 
247290ee3466SMark Haverkamp 	if (fsa_dev_ptr == NULL)
247390ee3466SMark Haverkamp 		return -1;
24741da177e4SLinus Torvalds 	/*
24751da177e4SLinus Torvalds 	 *	If the bus, id or lun is out of range, return fail
24761da177e4SLinus Torvalds 	 *	Test does not apply to ID 16, the pseudo id for the controller
24771da177e4SLinus Torvalds 	 *	itself.
24781da177e4SLinus Torvalds 	 */
24791a655040SSalyzyn, Mark 	cid = scmd_id(scsicmd);
24801a655040SSalyzyn, Mark 	if (cid != host->this_id) {
24811a655040SSalyzyn, Mark 		if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) {
24821a655040SSalyzyn, Mark 			if((cid >= dev->maximum_num_containers) ||
2483e5718774SMark Haverkamp 					(scsicmd->device->lun != 0)) {
24841da177e4SLinus Torvalds 				scsicmd->result = DID_NO_CONNECT << 16;
2485c4e2fbcaSRaghava Aditya Renukunta 				goto scsi_done_ret;
24861da177e4SLinus Torvalds 			}
24871da177e4SLinus Torvalds 
24881da177e4SLinus Torvalds 			/*
24891da177e4SLinus Torvalds 			 *	If the target container doesn't exist, it may have
24901da177e4SLinus Torvalds 			 *	been newly created
24911da177e4SLinus Torvalds 			 */
2492655d722cSMark Salyzyn 			if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
2493655d722cSMark Salyzyn 			  (fsa_dev_ptr[cid].sense_data.sense_key ==
2494655d722cSMark Salyzyn 			   NOT_READY)) {
24951da177e4SLinus Torvalds 				switch (scsicmd->cmnd[0]) {
2496eb846d9fSHannes Reinecke 				case SERVICE_ACTION_IN_16:
24977a8cf29dSMark Haverkamp 					if (!(dev->raw_io_interface) ||
24987a8cf29dSMark Haverkamp 					    !(dev->raw_io_64) ||
24997a8cf29dSMark Haverkamp 					    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
25007a8cf29dSMark Haverkamp 						break;
25011da177e4SLinus Torvalds 				case INQUIRY:
25021da177e4SLinus Torvalds 				case READ_CAPACITY:
25031da177e4SLinus Torvalds 				case TEST_UNIT_READY:
25048c867b25SMark Haverkamp 					if (dev->in_reset)
25058c867b25SMark Haverkamp 						return -1;
2506fe76df42SMark Haverkamp 					return _aac_probe_container(scsicmd,
2507fe76df42SMark Haverkamp 							aac_probe_container_callback2);
25081da177e4SLinus Torvalds 				default:
25091da177e4SLinus Torvalds 					break;
25101da177e4SLinus Torvalds 				}
25111da177e4SLinus Torvalds 			}
25121da177e4SLinus Torvalds 		} else {  /* check for physical non-dasd devices */
2513cb1042f2SSalyzyn, Mark 			if (dev->nondasd_support || expose_physicals ||
2514cb1042f2SSalyzyn, Mark 					dev->jbod) {
25158c867b25SMark Haverkamp 				if (dev->in_reset)
25168c867b25SMark Haverkamp 					return -1;
25171da177e4SLinus Torvalds 				return aac_send_srb_fib(scsicmd);
25181da177e4SLinus Torvalds 			} else {
25191da177e4SLinus Torvalds 				scsicmd->result = DID_NO_CONNECT << 16;
2520c4e2fbcaSRaghava Aditya Renukunta 				goto scsi_done_ret;
25211da177e4SLinus Torvalds 			}
25221da177e4SLinus Torvalds 		}
25231da177e4SLinus Torvalds 	}
25241da177e4SLinus Torvalds 	/*
25251da177e4SLinus Torvalds 	 * else Command for the controller itself
25261da177e4SLinus Torvalds 	 */
25271da177e4SLinus Torvalds 	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
25281da177e4SLinus Torvalds 		(scsicmd->cmnd[0] != TEST_UNIT_READY))
25291da177e4SLinus Torvalds 	{
25301da177e4SLinus Torvalds 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
25311da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
25328e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
25338e31e607SSalyzyn, Mark 		  ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
25348e31e607SSalyzyn, Mark 		  ASENCODE_INVALID_COMMAND, 0, 0);
25351da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
25363ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
25373ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
2538c4e2fbcaSRaghava Aditya Renukunta 		goto scsi_done_ret;
25391da177e4SLinus Torvalds 	}
25401da177e4SLinus Torvalds 
25411da177e4SLinus Torvalds 	switch (scsicmd->cmnd[0]) {
2542c4e2fbcaSRaghava Aditya Renukunta 	case READ_6:
2543c4e2fbcaSRaghava Aditya Renukunta 	case READ_10:
2544c4e2fbcaSRaghava Aditya Renukunta 	case READ_12:
2545c4e2fbcaSRaghava Aditya Renukunta 	case READ_16:
2546c4e2fbcaSRaghava Aditya Renukunta 		if (dev->in_reset)
2547c4e2fbcaSRaghava Aditya Renukunta 			return -1;
2548c4e2fbcaSRaghava Aditya Renukunta 		return aac_read(scsicmd);
2549c4e2fbcaSRaghava Aditya Renukunta 
2550c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_6:
2551c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_10:
2552c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_12:
2553c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_16:
2554c4e2fbcaSRaghava Aditya Renukunta 		if (dev->in_reset)
2555c4e2fbcaSRaghava Aditya Renukunta 			return -1;
2556c4e2fbcaSRaghava Aditya Renukunta 		return aac_write(scsicmd);
2557c4e2fbcaSRaghava Aditya Renukunta 
2558c4e2fbcaSRaghava Aditya Renukunta 	case SYNCHRONIZE_CACHE:
2559c4e2fbcaSRaghava Aditya Renukunta 		if (((aac_cache & 6) == 6) && dev->cache_protected) {
2560c4e2fbcaSRaghava Aditya Renukunta 			scsicmd->result = AAC_STAT_GOOD;
2561c4e2fbcaSRaghava Aditya Renukunta 			break;
2562c4e2fbcaSRaghava Aditya Renukunta 		}
2563c4e2fbcaSRaghava Aditya Renukunta 		/* Issue FIB to tell Firmware to flush it's cache */
2564c4e2fbcaSRaghava Aditya Renukunta 		if ((aac_cache & 6) != 2)
2565c4e2fbcaSRaghava Aditya Renukunta 			return aac_synchronize(scsicmd);
25661da177e4SLinus Torvalds 	case INQUIRY:
25671da177e4SLinus Torvalds 	{
25683b2946ccSMark Haverkamp 		struct inquiry_data inq_data;
25691da177e4SLinus Torvalds 
25701a655040SSalyzyn, Mark 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
25713b2946ccSMark Haverkamp 		memset(&inq_data, 0, sizeof (struct inquiry_data));
25721da177e4SLinus Torvalds 
2573d8e96507SLeubner, Achim 		if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) {
257488e2f98eSSalyzyn, Mark 			char *arr = (char *)&inq_data;
257588e2f98eSSalyzyn, Mark 
257688e2f98eSSalyzyn, Mark 			/* EVPD bit set */
257788e2f98eSSalyzyn, Mark 			arr[0] = (scmd_id(scsicmd) == host->this_id) ?
257888e2f98eSSalyzyn, Mark 			  INQD_PDT_PROC : INQD_PDT_DA;
257988e2f98eSSalyzyn, Mark 			if (scsicmd->cmnd[2] == 0) {
258088e2f98eSSalyzyn, Mark 				/* supported vital product data pages */
25815d910649SMahesh Rajashekhara 				arr[3] = 3;
258288e2f98eSSalyzyn, Mark 				arr[4] = 0x0;
258388e2f98eSSalyzyn, Mark 				arr[5] = 0x80;
25845d910649SMahesh Rajashekhara 				arr[6] = 0x83;
258588e2f98eSSalyzyn, Mark 				arr[1] = scsicmd->cmnd[2];
2586d4345028SFUJITA Tomonori 				scsi_sg_copy_from_buffer(scsicmd, &inq_data,
258788e2f98eSSalyzyn, Mark 							 sizeof(inq_data));
2588c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->result = AAC_STAT_GOOD;
258988e2f98eSSalyzyn, Mark 			} else if (scsicmd->cmnd[2] == 0x80) {
259088e2f98eSSalyzyn, Mark 				/* unit serial number page */
259188e2f98eSSalyzyn, Mark 				arr[3] = setinqserial(dev, &arr[4],
259288e2f98eSSalyzyn, Mark 				  scmd_id(scsicmd));
259388e2f98eSSalyzyn, Mark 				arr[1] = scsicmd->cmnd[2];
2594d4345028SFUJITA Tomonori 				scsi_sg_copy_from_buffer(scsicmd, &inq_data,
259588e2f98eSSalyzyn, Mark 							 sizeof(inq_data));
2596d8e96507SLeubner, Achim 				if (aac_wwn != 2)
2597d8e96507SLeubner, Achim 					return aac_get_container_serial(
2598d8e96507SLeubner, Achim 						scsicmd);
2599c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->result = AAC_STAT_GOOD;
26005d910649SMahesh Rajashekhara 			} else if (scsicmd->cmnd[2] == 0x83) {
26015d910649SMahesh Rajashekhara 				/* vpd page 0x83 - Device Identification Page */
26025d910649SMahesh Rajashekhara 				char *sno = (char *)&inq_data;
26035d910649SMahesh Rajashekhara 				sno[3] = setinqserial(dev, &sno[4],
26045d910649SMahesh Rajashekhara 						      scmd_id(scsicmd));
26055d910649SMahesh Rajashekhara 				if (aac_wwn != 2)
26065d910649SMahesh Rajashekhara 					return aac_get_container_serial(
26075d910649SMahesh Rajashekhara 						scsicmd);
2608c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->result = AAC_STAT_GOOD;
260988e2f98eSSalyzyn, Mark 			} else {
261088e2f98eSSalyzyn, Mark 				/* vpd page not implemented */
261188e2f98eSSalyzyn, Mark 				scsicmd->result = DID_OK << 16 |
261288e2f98eSSalyzyn, Mark 				  COMMAND_COMPLETE << 8 |
261388e2f98eSSalyzyn, Mark 				  SAM_STAT_CHECK_CONDITION;
26148e31e607SSalyzyn, Mark 				set_sense(&dev->fsa_dev[cid].sense_data,
26158e31e607SSalyzyn, Mark 				  ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD,
26168e31e607SSalyzyn, Mark 				  ASENCODE_NO_SENSE, 7, 2);
261788e2f98eSSalyzyn, Mark 				memcpy(scsicmd->sense_buffer,
261888e2f98eSSalyzyn, Mark 				  &dev->fsa_dev[cid].sense_data,
26193ace426fSSalyzyn, Mark 				  min_t(size_t,
26203ace426fSSalyzyn, Mark 					sizeof(dev->fsa_dev[cid].sense_data),
26213ace426fSSalyzyn, Mark 					SCSI_SENSE_BUFFERSIZE));
262288e2f98eSSalyzyn, Mark 			}
2623c4e2fbcaSRaghava Aditya Renukunta 			break;
262488e2f98eSSalyzyn, Mark 		}
26253b2946ccSMark Haverkamp 		inq_data.inqd_ver = 2;	/* claim compliance to SCSI-2 */
26263b2946ccSMark Haverkamp 		inq_data.inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
26273b2946ccSMark Haverkamp 		inq_data.inqd_len = 31;
26281da177e4SLinus Torvalds 		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
26293b2946ccSMark Haverkamp 		inq_data.inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
26301da177e4SLinus Torvalds 		/*
26311da177e4SLinus Torvalds 		 *	Set the Vendor, Product, and Revision Level
26321da177e4SLinus Torvalds 		 *	see: <vendor>.c i.e. aac.c
26331da177e4SLinus Torvalds 		 */
26341a655040SSalyzyn, Mark 		if (cid == host->this_id) {
26356391a113STobias Klauser 			setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
26363b2946ccSMark Haverkamp 			inq_data.inqd_pdt = INQD_PDT_PROC;	/* Processor device */
2637d4345028SFUJITA Tomonori 			scsi_sg_copy_from_buffer(scsicmd, &inq_data,
2638d4345028SFUJITA Tomonori 						 sizeof(inq_data));
2639c4e2fbcaSRaghava Aditya Renukunta 			scsicmd->result = AAC_STAT_GOOD;
2640c4e2fbcaSRaghava Aditya Renukunta 			break;
26411da177e4SLinus Torvalds 		}
26428c867b25SMark Haverkamp 		if (dev->in_reset)
26438c867b25SMark Haverkamp 			return -1;
2644794d0601SMark Haverkamp 		setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
26453b2946ccSMark Haverkamp 		inq_data.inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
2646d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
26479e7c349cSMark Haverkamp 		return aac_get_container_name(scsicmd);
26481da177e4SLinus Torvalds 	}
2649eb846d9fSHannes Reinecke 	case SERVICE_ACTION_IN_16:
26507a8cf29dSMark Haverkamp 		if (!(dev->raw_io_interface) ||
26517a8cf29dSMark Haverkamp 		    !(dev->raw_io_64) ||
26527a8cf29dSMark Haverkamp 		    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
26537a8cf29dSMark Haverkamp 			break;
26547a8cf29dSMark Haverkamp 	{
26557a8cf29dSMark Haverkamp 		u64 capacity;
265607ce5ebaSMark Haverkamp 		char cp[13];
2657b271f1c8SFUJITA Tomonori 		unsigned int alloc_len;
26587a8cf29dSMark Haverkamp 
26597a8cf29dSMark Haverkamp 		dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
26607a8cf29dSMark Haverkamp 		capacity = fsa_dev_ptr[cid].size - 1;
26617a8cf29dSMark Haverkamp 		cp[0] = (capacity >> 56) & 0xff;
26627a8cf29dSMark Haverkamp 		cp[1] = (capacity >> 48) & 0xff;
26637a8cf29dSMark Haverkamp 		cp[2] = (capacity >> 40) & 0xff;
26647a8cf29dSMark Haverkamp 		cp[3] = (capacity >> 32) & 0xff;
26657a8cf29dSMark Haverkamp 		cp[4] = (capacity >> 24) & 0xff;
26667a8cf29dSMark Haverkamp 		cp[5] = (capacity >> 16) & 0xff;
26677a8cf29dSMark Haverkamp 		cp[6] = (capacity >> 8) & 0xff;
26687a8cf29dSMark Haverkamp 		cp[7] = (capacity >> 0) & 0xff;
2669b836439fSMahesh Rajashekhara 		cp[8] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff;
2670b836439fSMahesh Rajashekhara 		cp[9] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2671b836439fSMahesh Rajashekhara 		cp[10] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff;
2672b836439fSMahesh Rajashekhara 		cp[11] = (fsa_dev_ptr[cid].block_size) & 0xff;
267307ce5ebaSMark Haverkamp 		cp[12] = 0;
267407ce5ebaSMark Haverkamp 
2675b271f1c8SFUJITA Tomonori 		alloc_len = ((scsicmd->cmnd[10] << 24)
2676b271f1c8SFUJITA Tomonori 			     + (scsicmd->cmnd[11] << 16)
2677b271f1c8SFUJITA Tomonori 			     + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]);
2678b271f1c8SFUJITA Tomonori 
2679b271f1c8SFUJITA Tomonori 		alloc_len = min_t(size_t, alloc_len, sizeof(cp));
2680d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len);
2681b271f1c8SFUJITA Tomonori 		if (alloc_len < scsi_bufflen(scsicmd))
2682b271f1c8SFUJITA Tomonori 			scsi_set_resid(scsicmd,
2683b271f1c8SFUJITA Tomonori 				       scsi_bufflen(scsicmd) - alloc_len);
26847a8cf29dSMark Haverkamp 
26857a8cf29dSMark Haverkamp 		/* Do not cache partition table for arrays */
26867a8cf29dSMark Haverkamp 		scsicmd->device->removable = 1;
26877a8cf29dSMark Haverkamp 
2688c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2689c4e2fbcaSRaghava Aditya Renukunta 		break;
26907a8cf29dSMark Haverkamp 	}
26917a8cf29dSMark Haverkamp 
26921da177e4SLinus Torvalds 	case READ_CAPACITY:
26931da177e4SLinus Torvalds 	{
26941da177e4SLinus Torvalds 		u32 capacity;
26953b2946ccSMark Haverkamp 		char cp[8];
26961da177e4SLinus Torvalds 
26971da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
26987a8cf29dSMark Haverkamp 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
26991da177e4SLinus Torvalds 			capacity = fsa_dev_ptr[cid].size - 1;
27001da177e4SLinus Torvalds 		else
27011da177e4SLinus Torvalds 			capacity = (u32)-1;
27023b2946ccSMark Haverkamp 
27031da177e4SLinus Torvalds 		cp[0] = (capacity >> 24) & 0xff;
27041da177e4SLinus Torvalds 		cp[1] = (capacity >> 16) & 0xff;
27051da177e4SLinus Torvalds 		cp[2] = (capacity >> 8) & 0xff;
27061da177e4SLinus Torvalds 		cp[3] = (capacity >> 0) & 0xff;
2707b836439fSMahesh Rajashekhara 		cp[4] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff;
2708b836439fSMahesh Rajashekhara 		cp[5] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2709b836439fSMahesh Rajashekhara 		cp[6] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff;
2710b836439fSMahesh Rajashekhara 		cp[7] = (fsa_dev_ptr[cid].block_size) & 0xff;
2711d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
27127a8cf29dSMark Haverkamp 		/* Do not cache partition table for arrays */
27137a8cf29dSMark Haverkamp 		scsicmd->device->removable = 1;
2714c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2715c4e2fbcaSRaghava Aditya Renukunta 		break;
27161da177e4SLinus Torvalds 	}
27171da177e4SLinus Torvalds 
27181da177e4SLinus Torvalds 	case MODE_SENSE:
27191da177e4SLinus Torvalds 	{
27209d399cc7SSalyzyn, Mark 		int mode_buf_length = 4;
2721b836439fSMahesh Rajashekhara 		u32 capacity;
2722b836439fSMahesh Rajashekhara 		aac_modep_data mpd;
2723b836439fSMahesh Rajashekhara 
2724b836439fSMahesh Rajashekhara 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
2725b836439fSMahesh Rajashekhara 			capacity = fsa_dev_ptr[cid].size - 1;
2726b836439fSMahesh Rajashekhara 		else
2727b836439fSMahesh Rajashekhara 			capacity = (u32)-1;
27281da177e4SLinus Torvalds 
27291da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "MODE SENSE command.\n"));
2730b836439fSMahesh Rajashekhara 		memset((char *)&mpd, 0, sizeof(aac_modep_data));
2731b836439fSMahesh Rajashekhara 
2732b836439fSMahesh Rajashekhara 		/* Mode data length */
2733b836439fSMahesh Rajashekhara 		mpd.hd.data_length = sizeof(mpd.hd) - 1;
2734b836439fSMahesh Rajashekhara 		/* Medium type - default */
2735b836439fSMahesh Rajashekhara 		mpd.hd.med_type = 0;
2736b836439fSMahesh Rajashekhara 		/* Device-specific param,
27379d399cc7SSalyzyn, Mark 		   bit 8: 0/1 = write enabled/protected
27389d399cc7SSalyzyn, Mark 		   bit 4: 0/1 = FUA enabled */
2739b836439fSMahesh Rajashekhara 		mpd.hd.dev_par = 0;
2740b836439fSMahesh Rajashekhara 
274195e852e1SSalyzyn, Mark 		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
2742b836439fSMahesh Rajashekhara 			mpd.hd.dev_par = 0x10;
2743b836439fSMahesh Rajashekhara 		if (scsicmd->cmnd[1] & 0x8)
2744b836439fSMahesh Rajashekhara 			mpd.hd.bd_length = 0;	/* Block descriptor length */
2745b836439fSMahesh Rajashekhara 		else {
2746b836439fSMahesh Rajashekhara 			mpd.hd.bd_length = sizeof(mpd.bd);
2747b836439fSMahesh Rajashekhara 			mpd.hd.data_length += mpd.hd.bd_length;
2748b836439fSMahesh Rajashekhara 			mpd.bd.block_length[0] =
2749b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2750b836439fSMahesh Rajashekhara 			mpd.bd.block_length[1] =
2751b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 8) &  0xff;
2752b836439fSMahesh Rajashekhara 			mpd.bd.block_length[2] =
2753b836439fSMahesh Rajashekhara 				fsa_dev_ptr[cid].block_size  & 0xff;
27545d910649SMahesh Rajashekhara 
27555d910649SMahesh Rajashekhara 			mpd.mpc_buf[0] = scsicmd->cmnd[2];
27565d910649SMahesh Rajashekhara 			if (scsicmd->cmnd[2] == 0x1C) {
27575d910649SMahesh Rajashekhara 				/* page length */
27585d910649SMahesh Rajashekhara 				mpd.mpc_buf[1] = 0xa;
27595d910649SMahesh Rajashekhara 				/* Mode data length */
27605d910649SMahesh Rajashekhara 				mpd.hd.data_length = 23;
27615d910649SMahesh Rajashekhara 			} else {
27625d910649SMahesh Rajashekhara 				/* Mode data length */
27635d910649SMahesh Rajashekhara 				mpd.hd.data_length = 15;
27645d910649SMahesh Rajashekhara 			}
27655d910649SMahesh Rajashekhara 
2766b836439fSMahesh Rajashekhara 			if (capacity > 0xffffff) {
2767b836439fSMahesh Rajashekhara 				mpd.bd.block_count[0] = 0xff;
2768b836439fSMahesh Rajashekhara 				mpd.bd.block_count[1] = 0xff;
2769b836439fSMahesh Rajashekhara 				mpd.bd.block_count[2] = 0xff;
2770b836439fSMahesh Rajashekhara 			} else {
2771b836439fSMahesh Rajashekhara 				mpd.bd.block_count[0] = (capacity >> 16) & 0xff;
2772b836439fSMahesh Rajashekhara 				mpd.bd.block_count[1] = (capacity >> 8) & 0xff;
2773b836439fSMahesh Rajashekhara 				mpd.bd.block_count[2] = capacity  & 0xff;
2774b836439fSMahesh Rajashekhara 			}
2775b836439fSMahesh Rajashekhara 		}
27769d399cc7SSalyzyn, Mark 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
27779d399cc7SSalyzyn, Mark 		  ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
2778b836439fSMahesh Rajashekhara 			mpd.hd.data_length += 3;
2779b836439fSMahesh Rajashekhara 			mpd.mpc_buf[0] = 8;
2780b836439fSMahesh Rajashekhara 			mpd.mpc_buf[1] = 1;
2781b836439fSMahesh Rajashekhara 			mpd.mpc_buf[2] = ((aac_cache & 6) == 2)
278295e852e1SSalyzyn, Mark 				? 0 : 0x04; /* WCE */
2783b836439fSMahesh Rajashekhara 			mode_buf_length = sizeof(mpd);
27845d910649SMahesh Rajashekhara 		}
27855d910649SMahesh Rajashekhara 
27869d399cc7SSalyzyn, Mark 		if (mode_buf_length > scsicmd->cmnd[4])
27879d399cc7SSalyzyn, Mark 			mode_buf_length = scsicmd->cmnd[4];
27885d910649SMahesh Rajashekhara 		else
27895d910649SMahesh Rajashekhara 			mode_buf_length = sizeof(mpd);
2790b836439fSMahesh Rajashekhara 		scsi_sg_copy_from_buffer(scsicmd,
2791b836439fSMahesh Rajashekhara 					 (char *)&mpd,
2792b836439fSMahesh Rajashekhara 					 mode_buf_length);
2793c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2794c4e2fbcaSRaghava Aditya Renukunta 		break;
27951da177e4SLinus Torvalds 	}
27961da177e4SLinus Torvalds 	case MODE_SENSE_10:
27971da177e4SLinus Torvalds 	{
2798b836439fSMahesh Rajashekhara 		u32 capacity;
27999d399cc7SSalyzyn, Mark 		int mode_buf_length = 8;
2800b836439fSMahesh Rajashekhara 		aac_modep10_data mpd10;
2801b836439fSMahesh Rajashekhara 
2802b836439fSMahesh Rajashekhara 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
2803b836439fSMahesh Rajashekhara 			capacity = fsa_dev_ptr[cid].size - 1;
2804b836439fSMahesh Rajashekhara 		else
2805b836439fSMahesh Rajashekhara 			capacity = (u32)-1;
28061da177e4SLinus Torvalds 
28071da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
2808b836439fSMahesh Rajashekhara 		memset((char *)&mpd10, 0, sizeof(aac_modep10_data));
2809b836439fSMahesh Rajashekhara 		/* Mode data length (MSB) */
2810b836439fSMahesh Rajashekhara 		mpd10.hd.data_length[0] = 0;
2811b836439fSMahesh Rajashekhara 		/* Mode data length (LSB) */
2812b836439fSMahesh Rajashekhara 		mpd10.hd.data_length[1] = sizeof(mpd10.hd) - 1;
2813b836439fSMahesh Rajashekhara 		/* Medium type - default */
2814b836439fSMahesh Rajashekhara 		mpd10.hd.med_type = 0;
2815b836439fSMahesh Rajashekhara 		/* Device-specific param,
28169d399cc7SSalyzyn, Mark 		   bit 8: 0/1 = write enabled/protected
28179d399cc7SSalyzyn, Mark 		   bit 4: 0/1 = FUA enabled */
2818b836439fSMahesh Rajashekhara 		mpd10.hd.dev_par = 0;
2819b836439fSMahesh Rajashekhara 
282095e852e1SSalyzyn, Mark 		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
2821b836439fSMahesh Rajashekhara 			mpd10.hd.dev_par = 0x10;
2822b836439fSMahesh Rajashekhara 		mpd10.hd.rsrvd[0] = 0;	/* reserved */
2823b836439fSMahesh Rajashekhara 		mpd10.hd.rsrvd[1] = 0;	/* reserved */
2824b836439fSMahesh Rajashekhara 		if (scsicmd->cmnd[1] & 0x8) {
2825b836439fSMahesh Rajashekhara 			/* Block descriptor length (MSB) */
2826b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[0] = 0;
2827b836439fSMahesh Rajashekhara 			/* Block descriptor length (LSB) */
2828b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[1] = 0;
2829b836439fSMahesh Rajashekhara 		} else {
2830b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[0] = 0;
2831b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[1] = sizeof(mpd10.bd);
2832b836439fSMahesh Rajashekhara 
2833b836439fSMahesh Rajashekhara 			mpd10.hd.data_length[1] += mpd10.hd.bd_length[1];
2834b836439fSMahesh Rajashekhara 
2835b836439fSMahesh Rajashekhara 			mpd10.bd.block_length[0] =
2836b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2837b836439fSMahesh Rajashekhara 			mpd10.bd.block_length[1] =
2838b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 8) & 0xff;
2839b836439fSMahesh Rajashekhara 			mpd10.bd.block_length[2] =
2840b836439fSMahesh Rajashekhara 				fsa_dev_ptr[cid].block_size  & 0xff;
2841b836439fSMahesh Rajashekhara 
2842b836439fSMahesh Rajashekhara 			if (capacity > 0xffffff) {
2843b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[0] = 0xff;
2844b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[1] = 0xff;
2845b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[2] = 0xff;
2846b836439fSMahesh Rajashekhara 			} else {
2847b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[0] =
2848b836439fSMahesh Rajashekhara 					(capacity >> 16) & 0xff;
2849b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[1] =
2850b836439fSMahesh Rajashekhara 					(capacity >> 8) & 0xff;
2851b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[2] =
2852b836439fSMahesh Rajashekhara 					capacity  & 0xff;
2853b836439fSMahesh Rajashekhara 			}
2854b836439fSMahesh Rajashekhara 		}
28559d399cc7SSalyzyn, Mark 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
28569d399cc7SSalyzyn, Mark 		  ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
2857b836439fSMahesh Rajashekhara 			mpd10.hd.data_length[1] += 3;
2858b836439fSMahesh Rajashekhara 			mpd10.mpc_buf[0] = 8;
2859b836439fSMahesh Rajashekhara 			mpd10.mpc_buf[1] = 1;
2860b836439fSMahesh Rajashekhara 			mpd10.mpc_buf[2] = ((aac_cache & 6) == 2)
286195e852e1SSalyzyn, Mark 				? 0 : 0x04; /* WCE */
2862b836439fSMahesh Rajashekhara 			mode_buf_length = sizeof(mpd10);
28639d399cc7SSalyzyn, Mark 			if (mode_buf_length > scsicmd->cmnd[8])
28649d399cc7SSalyzyn, Mark 				mode_buf_length = scsicmd->cmnd[8];
28659d399cc7SSalyzyn, Mark 		}
2866b836439fSMahesh Rajashekhara 		scsi_sg_copy_from_buffer(scsicmd,
2867b836439fSMahesh Rajashekhara 					 (char *)&mpd10,
2868b836439fSMahesh Rajashekhara 					 mode_buf_length);
28691da177e4SLinus Torvalds 
2870c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2871c4e2fbcaSRaghava Aditya Renukunta 		break;
28721da177e4SLinus Torvalds 	}
28731da177e4SLinus Torvalds 	case REQUEST_SENSE:
28741da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
2875c4e2fbcaSRaghava Aditya Renukunta 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2876c4e2fbcaSRaghava Aditya Renukunta 				sizeof(struct sense_data));
2877c4e2fbcaSRaghava Aditya Renukunta 		memset(&dev->fsa_dev[cid].sense_data, 0,
2878c4e2fbcaSRaghava Aditya Renukunta 				sizeof(struct sense_data));
2879c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2880c4e2fbcaSRaghava Aditya Renukunta 		break;
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 	case ALLOW_MEDIUM_REMOVAL:
28831da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "LOCK command.\n"));
28841da177e4SLinus Torvalds 		if (scsicmd->cmnd[4])
28851da177e4SLinus Torvalds 			fsa_dev_ptr[cid].locked = 1;
28861da177e4SLinus Torvalds 		else
28871da177e4SLinus Torvalds 			fsa_dev_ptr[cid].locked = 0;
28881da177e4SLinus Torvalds 
2889c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2890c4e2fbcaSRaghava Aditya Renukunta 		break;
28911da177e4SLinus Torvalds 	/*
28921da177e4SLinus Torvalds 	 *	These commands are all No-Ops
28931da177e4SLinus Torvalds 	 */
28941da177e4SLinus Torvalds 	case TEST_UNIT_READY:
2895655d722cSMark Salyzyn 		if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
2896655d722cSMark Salyzyn 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2897655d722cSMark Salyzyn 				SAM_STAT_CHECK_CONDITION;
2898655d722cSMark Salyzyn 			set_sense(&dev->fsa_dev[cid].sense_data,
2899655d722cSMark Salyzyn 				  NOT_READY, SENCODE_BECOMING_READY,
2900655d722cSMark Salyzyn 				  ASENCODE_BECOMING_READY, 0, 0);
2901655d722cSMark Salyzyn 			memcpy(scsicmd->sense_buffer,
2902655d722cSMark Salyzyn 			       &dev->fsa_dev[cid].sense_data,
2903655d722cSMark Salyzyn 			       min_t(size_t,
2904655d722cSMark Salyzyn 				     sizeof(dev->fsa_dev[cid].sense_data),
2905655d722cSMark Salyzyn 				     SCSI_SENSE_BUFFERSIZE));
2906c4e2fbcaSRaghava Aditya Renukunta 		break;
2907655d722cSMark Salyzyn 		}
29081da177e4SLinus Torvalds 	case RESERVE:
29091da177e4SLinus Torvalds 	case RELEASE:
29101da177e4SLinus Torvalds 	case REZERO_UNIT:
29111da177e4SLinus Torvalds 	case REASSIGN_BLOCKS:
29121da177e4SLinus Torvalds 	case SEEK_10:
2913c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2914c4e2fbcaSRaghava Aditya Renukunta 		break;
2915655d722cSMark Salyzyn 
2916655d722cSMark Salyzyn 	case START_STOP:
2917655d722cSMark Salyzyn 		return aac_start_stop(scsicmd);
29181da177e4SLinus Torvalds 
291995e852e1SSalyzyn, Mark 	/* FALLTHRU */
29201da177e4SLinus Torvalds 	default:
29211da177e4SLinus Torvalds 	/*
29221da177e4SLinus Torvalds 	 *	Unhandled commands
29231da177e4SLinus Torvalds 	 */
2924c4e2fbcaSRaghava Aditya Renukunta 		dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n",
2925c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->cmnd[0]));
2926c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2927c4e2fbcaSRaghava Aditya Renukunta 				SAM_STAT_CHECK_CONDITION;
29288e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
29291da177e4SLinus Torvalds 			  ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
29308e31e607SSalyzyn, Mark 			  ASENCODE_INVALID_COMMAND, 0, 0);
29311da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
29323ace426fSSalyzyn, Mark 				min_t(size_t,
29333ace426fSSalyzyn, Mark 				      sizeof(dev->fsa_dev[cid].sense_data),
29343ace426fSSalyzyn, Mark 				      SCSI_SENSE_BUFFERSIZE));
2935c4e2fbcaSRaghava Aditya Renukunta 	}
2936c4e2fbcaSRaghava Aditya Renukunta 
2937c4e2fbcaSRaghava Aditya Renukunta scsi_done_ret:
2938c4e2fbcaSRaghava Aditya Renukunta 
29391da177e4SLinus Torvalds 	scsicmd->scsi_done(scsicmd);
29401da177e4SLinus Torvalds 	return 0;
29411da177e4SLinus Torvalds }
29421da177e4SLinus Torvalds 
29431da177e4SLinus Torvalds static int query_disk(struct aac_dev *dev, void __user *arg)
29441da177e4SLinus Torvalds {
29451da177e4SLinus Torvalds 	struct aac_query_disk qd;
29461da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
29471da177e4SLinus Torvalds 
29481da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
294990ee3466SMark Haverkamp 	if (!fsa_dev_ptr)
295065101355SMark Haverkamp 		return -EBUSY;
29511da177e4SLinus Torvalds 	if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
29521da177e4SLinus Torvalds 		return -EFAULT;
29531da177e4SLinus Torvalds 	if (qd.cnum == -1)
2954e5718774SMark Haverkamp 		qd.cnum = qd.id;
29551da177e4SLinus Torvalds 	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
29561da177e4SLinus Torvalds 	{
29571da177e4SLinus Torvalds 		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
29581da177e4SLinus Torvalds 			return -EINVAL;
29591da177e4SLinus Torvalds 		qd.instance = dev->scsi_host_ptr->host_no;
29601da177e4SLinus Torvalds 		qd.bus = 0;
29611da177e4SLinus Torvalds 		qd.id = CONTAINER_TO_ID(qd.cnum);
29621da177e4SLinus Torvalds 		qd.lun = CONTAINER_TO_LUN(qd.cnum);
29631da177e4SLinus Torvalds 	}
29641da177e4SLinus Torvalds 	else return -EINVAL;
29651da177e4SLinus Torvalds 
2966fd622b1bSSalyzyn, Mark 	qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
29671da177e4SLinus Torvalds 	qd.locked = fsa_dev_ptr[qd.cnum].locked;
29681da177e4SLinus Torvalds 	qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
29691da177e4SLinus Torvalds 
29701da177e4SLinus Torvalds 	if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
29711da177e4SLinus Torvalds 		qd.unmapped = 1;
29721da177e4SLinus Torvalds 	else
29731da177e4SLinus Torvalds 		qd.unmapped = 0;
29741da177e4SLinus Torvalds 
29751da177e4SLinus Torvalds 	strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
29761da177e4SLinus Torvalds 	  min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
29771da177e4SLinus Torvalds 
29781da177e4SLinus Torvalds 	if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
29791da177e4SLinus Torvalds 		return -EFAULT;
29801da177e4SLinus Torvalds 	return 0;
29811da177e4SLinus Torvalds }
29821da177e4SLinus Torvalds 
29831da177e4SLinus Torvalds static int force_delete_disk(struct aac_dev *dev, void __user *arg)
29841da177e4SLinus Torvalds {
29851da177e4SLinus Torvalds 	struct aac_delete_disk dd;
29861da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
29871da177e4SLinus Torvalds 
29881da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
298965101355SMark Haverkamp 	if (!fsa_dev_ptr)
299065101355SMark Haverkamp 		return -EBUSY;
29911da177e4SLinus Torvalds 
29921da177e4SLinus Torvalds 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
29931da177e4SLinus Torvalds 		return -EFAULT;
29941da177e4SLinus Torvalds 
29951da177e4SLinus Torvalds 	if (dd.cnum >= dev->maximum_num_containers)
29961da177e4SLinus Torvalds 		return -EINVAL;
29971da177e4SLinus Torvalds 	/*
29981da177e4SLinus Torvalds 	 *	Mark this container as being deleted.
29991da177e4SLinus Torvalds 	 */
30001da177e4SLinus Torvalds 	fsa_dev_ptr[dd.cnum].deleted = 1;
30011da177e4SLinus Torvalds 	/*
30021da177e4SLinus Torvalds 	 *	Mark the container as no longer valid
30031da177e4SLinus Torvalds 	 */
30041da177e4SLinus Torvalds 	fsa_dev_ptr[dd.cnum].valid = 0;
30051da177e4SLinus Torvalds 	return 0;
30061da177e4SLinus Torvalds }
30071da177e4SLinus Torvalds 
30081da177e4SLinus Torvalds static int delete_disk(struct aac_dev *dev, void __user *arg)
30091da177e4SLinus Torvalds {
30101da177e4SLinus Torvalds 	struct aac_delete_disk dd;
30111da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
30121da177e4SLinus Torvalds 
30131da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
301490ee3466SMark Haverkamp 	if (!fsa_dev_ptr)
301565101355SMark Haverkamp 		return -EBUSY;
30161da177e4SLinus Torvalds 
30171da177e4SLinus Torvalds 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
30181da177e4SLinus Torvalds 		return -EFAULT;
30191da177e4SLinus Torvalds 
30201da177e4SLinus Torvalds 	if (dd.cnum >= dev->maximum_num_containers)
30211da177e4SLinus Torvalds 		return -EINVAL;
30221da177e4SLinus Torvalds 	/*
30231da177e4SLinus Torvalds 	 *	If the container is locked, it can not be deleted by the API.
30241da177e4SLinus Torvalds 	 */
30251da177e4SLinus Torvalds 	if (fsa_dev_ptr[dd.cnum].locked)
30261da177e4SLinus Torvalds 		return -EBUSY;
30271da177e4SLinus Torvalds 	else {
30281da177e4SLinus Torvalds 		/*
30291da177e4SLinus Torvalds 		 *	Mark the container as no longer being valid.
30301da177e4SLinus Torvalds 		 */
30311da177e4SLinus Torvalds 		fsa_dev_ptr[dd.cnum].valid = 0;
30321da177e4SLinus Torvalds 		fsa_dev_ptr[dd.cnum].devname[0] = '\0';
30331da177e4SLinus Torvalds 		return 0;
30341da177e4SLinus Torvalds 	}
30351da177e4SLinus Torvalds }
30361da177e4SLinus Torvalds 
30371da177e4SLinus Torvalds int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
30381da177e4SLinus Torvalds {
30391da177e4SLinus Torvalds 	switch (cmd) {
30401da177e4SLinus Torvalds 	case FSACTL_QUERY_DISK:
30411da177e4SLinus Torvalds 		return query_disk(dev, arg);
30421da177e4SLinus Torvalds 	case FSACTL_DELETE_DISK:
30431da177e4SLinus Torvalds 		return delete_disk(dev, arg);
30441da177e4SLinus Torvalds 	case FSACTL_FORCE_DELETE_DISK:
30451da177e4SLinus Torvalds 		return force_delete_disk(dev, arg);
30461da177e4SLinus Torvalds 	case FSACTL_GET_CONTAINERS:
30471da177e4SLinus Torvalds 		return aac_get_containers(dev);
30481da177e4SLinus Torvalds 	default:
30491da177e4SLinus Torvalds 		return -ENOTTY;
30501da177e4SLinus Torvalds 	}
30511da177e4SLinus Torvalds }
30521da177e4SLinus Torvalds 
30531da177e4SLinus Torvalds /**
30541da177e4SLinus Torvalds  *
30551da177e4SLinus Torvalds  * aac_srb_callback
30561da177e4SLinus Torvalds  * @context: the context set in the fib - here it is scsi cmd
30571da177e4SLinus Torvalds  * @fibptr: pointer to the fib
30581da177e4SLinus Torvalds  *
30591da177e4SLinus Torvalds  * Handles the completion of a scsi command to a non dasd device
30601da177e4SLinus Torvalds  *
30611da177e4SLinus Torvalds  */
30621da177e4SLinus Torvalds 
30631da177e4SLinus Torvalds static void aac_srb_callback(void *context, struct fib * fibptr)
30641da177e4SLinus Torvalds {
30651da177e4SLinus Torvalds 	struct aac_dev *dev;
30661da177e4SLinus Torvalds 	struct aac_srb_reply *srbreply;
30671da177e4SLinus Torvalds 	struct scsi_cmnd *scsicmd;
30681da177e4SLinus Torvalds 
30691da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
307003d44337SMark Haverkamp 
307103d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
307203d44337SMark Haverkamp 		return;
307303d44337SMark Haverkamp 
3074125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
30754ec57fb4SRaghava Aditya Renukunta 
30761a655040SSalyzyn, Mark 	dev = fibptr->dev;
30771a655040SSalyzyn, Mark 
307855b87608SMahesh Rajashekhara 	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
30794ec57fb4SRaghava Aditya Renukunta 
30801da177e4SLinus Torvalds 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
308185d22bbfSMahesh Rajashekhara 
308285d22bbfSMahesh Rajashekhara 	if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
308385d22bbfSMahesh Rajashekhara 		/* fast response */
308485d22bbfSMahesh Rajashekhara 		srbreply->srb_status = cpu_to_le32(SRB_STATUS_SUCCESS);
308585d22bbfSMahesh Rajashekhara 		srbreply->scsi_status = cpu_to_le32(SAM_STAT_GOOD);
308685d22bbfSMahesh Rajashekhara 	} else {
30871da177e4SLinus Torvalds 		/*
30881da177e4SLinus Torvalds 		 *	Calculate resid for sg
30891da177e4SLinus Torvalds 		 */
3090727eead6SFUJITA Tomonori 		scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
3091727eead6SFUJITA Tomonori 				   - le32_to_cpu(srbreply->data_xfer_length));
30924ec57fb4SRaghava Aditya Renukunta 	}
30934ec57fb4SRaghava Aditya Renukunta 
30944ec57fb4SRaghava Aditya Renukunta 
30954ec57fb4SRaghava Aditya Renukunta 	scsi_dma_unmap(scsicmd);
30964ec57fb4SRaghava Aditya Renukunta 
30974ec57fb4SRaghava Aditya Renukunta 	/* expose physical device if expose_physicald flag is on */
30984ec57fb4SRaghava Aditya Renukunta 	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
30994ec57fb4SRaghava Aditya Renukunta 	  && expose_physicals > 0)
31004ec57fb4SRaghava Aditya Renukunta 		aac_expose_phy_device(scsicmd);
31014ec57fb4SRaghava Aditya Renukunta 
31021da177e4SLinus Torvalds 	/*
31031da177e4SLinus Torvalds 	 * First check the fib status
31041da177e4SLinus Torvalds 	 */
31051da177e4SLinus Torvalds 
31061da177e4SLinus Torvalds 	if (le32_to_cpu(srbreply->status) != ST_OK) {
31071da177e4SLinus Torvalds 		int len;
310855b87608SMahesh Rajashekhara 
31094ec57fb4SRaghava Aditya Renukunta 		pr_warn("aac_srb_callback: srb failed, status = %d\n",
31104ec57fb4SRaghava Aditya Renukunta 				le32_to_cpu(srbreply->status));
31113ace426fSSalyzyn, Mark 		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
31123ace426fSSalyzyn, Mark 			    SCSI_SENSE_BUFFERSIZE);
311355b87608SMahesh Rajashekhara 		scsicmd->result = DID_ERROR << 16
311455b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8
311555b87608SMahesh Rajashekhara 				| SAM_STAT_CHECK_CONDITION;
311655b87608SMahesh Rajashekhara 		memcpy(scsicmd->sense_buffer,
311755b87608SMahesh Rajashekhara 				srbreply->sense_data, len);
31181da177e4SLinus Torvalds 	}
31191da177e4SLinus Torvalds 
31201da177e4SLinus Torvalds 	/*
31211da177e4SLinus Torvalds 	 * Next check the srb status
31221da177e4SLinus Torvalds 	 */
31231da177e4SLinus Torvalds 	switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
31241da177e4SLinus Torvalds 	case SRB_STATUS_ERROR_RECOVERY:
31251da177e4SLinus Torvalds 	case SRB_STATUS_PENDING:
31261da177e4SLinus Torvalds 	case SRB_STATUS_SUCCESS:
31271da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
31281da177e4SLinus Torvalds 		break;
31291da177e4SLinus Torvalds 	case SRB_STATUS_DATA_OVERRUN:
31301da177e4SLinus Torvalds 		switch (scsicmd->cmnd[0]) {
31311da177e4SLinus Torvalds 		case  READ_6:
31321da177e4SLinus Torvalds 		case  WRITE_6:
31331da177e4SLinus Torvalds 		case  READ_10:
31341da177e4SLinus Torvalds 		case  WRITE_10:
31351da177e4SLinus Torvalds 		case  READ_12:
31361da177e4SLinus Torvalds 		case  WRITE_12:
31377a8cf29dSMark Haverkamp 		case  READ_16:
31387a8cf29dSMark Haverkamp 		case  WRITE_16:
313955b87608SMahesh Rajashekhara 			if (le32_to_cpu(srbreply->data_xfer_length)
314055b87608SMahesh Rajashekhara 						< scsicmd->underflow)
31414ec57fb4SRaghava Aditya Renukunta 				pr_warn("aacraid: SCSI CMD underflow\n");
314255b87608SMahesh Rajashekhara 			else
31434ec57fb4SRaghava Aditya Renukunta 				pr_warn("aacraid: SCSI CMD Data Overrun\n");
314455b87608SMahesh Rajashekhara 			scsicmd->result = DID_ERROR << 16
314555b87608SMahesh Rajashekhara 					| COMMAND_COMPLETE << 8;
31461da177e4SLinus Torvalds 			break;
31474ec57fb4SRaghava Aditya Renukunta 		case INQUIRY:
314855b87608SMahesh Rajashekhara 			scsicmd->result = DID_OK << 16
314955b87608SMahesh Rajashekhara 					| COMMAND_COMPLETE << 8;
31501da177e4SLinus Torvalds 			break;
31511da177e4SLinus Torvalds 		default:
31521da177e4SLinus Torvalds 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
31531da177e4SLinus Torvalds 			break;
31541da177e4SLinus Torvalds 		}
31551da177e4SLinus Torvalds 		break;
31561da177e4SLinus Torvalds 	case SRB_STATUS_ABORTED:
31571da177e4SLinus Torvalds 		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
31581da177e4SLinus Torvalds 		break;
31591da177e4SLinus Torvalds 	case SRB_STATUS_ABORT_FAILED:
316055b87608SMahesh Rajashekhara 		/*
316155b87608SMahesh Rajashekhara 		 * Not sure about this one - but assuming the
316255b87608SMahesh Rajashekhara 		 * hba was trying to abort for some reason
316355b87608SMahesh Rajashekhara 		 */
31641da177e4SLinus Torvalds 		scsicmd->result = DID_ERROR << 16 | ABORT << 8;
31651da177e4SLinus Torvalds 		break;
31661da177e4SLinus Torvalds 	case SRB_STATUS_PARITY_ERROR:
316755b87608SMahesh Rajashekhara 		scsicmd->result = DID_PARITY << 16
316855b87608SMahesh Rajashekhara 				| MSG_PARITY_ERROR << 8;
31691da177e4SLinus Torvalds 		break;
31701da177e4SLinus Torvalds 	case SRB_STATUS_NO_DEVICE:
31711da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_PATH_ID:
31721da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_TARGET_ID:
31731da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_LUN:
31741da177e4SLinus Torvalds 	case SRB_STATUS_SELECTION_TIMEOUT:
317555b87608SMahesh Rajashekhara 		scsicmd->result = DID_NO_CONNECT << 16
317655b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
31771da177e4SLinus Torvalds 		break;
31781da177e4SLinus Torvalds 
31791da177e4SLinus Torvalds 	case SRB_STATUS_COMMAND_TIMEOUT:
31801da177e4SLinus Torvalds 	case SRB_STATUS_TIMEOUT:
318155b87608SMahesh Rajashekhara 		scsicmd->result = DID_TIME_OUT << 16
318255b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
31831da177e4SLinus Torvalds 		break;
31841da177e4SLinus Torvalds 
31851da177e4SLinus Torvalds 	case SRB_STATUS_BUSY:
318655b87608SMahesh Rajashekhara 		scsicmd->result = DID_BUS_BUSY << 16
318755b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
31881da177e4SLinus Torvalds 		break;
31891da177e4SLinus Torvalds 
31901da177e4SLinus Torvalds 	case SRB_STATUS_BUS_RESET:
319155b87608SMahesh Rajashekhara 		scsicmd->result = DID_RESET << 16
319255b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
31931da177e4SLinus Torvalds 		break;
31941da177e4SLinus Torvalds 
31951da177e4SLinus Torvalds 	case SRB_STATUS_MESSAGE_REJECTED:
319655b87608SMahesh Rajashekhara 		scsicmd->result = DID_ERROR << 16
319755b87608SMahesh Rajashekhara 				| MESSAGE_REJECT << 8;
31981da177e4SLinus Torvalds 		break;
31991da177e4SLinus Torvalds 	case SRB_STATUS_REQUEST_FLUSHED:
32001da177e4SLinus Torvalds 	case SRB_STATUS_ERROR:
32011da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_REQUEST:
32021da177e4SLinus Torvalds 	case SRB_STATUS_REQUEST_SENSE_FAILED:
32031da177e4SLinus Torvalds 	case SRB_STATUS_NO_HBA:
32041da177e4SLinus Torvalds 	case SRB_STATUS_UNEXPECTED_BUS_FREE:
32051da177e4SLinus Torvalds 	case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
32061da177e4SLinus Torvalds 	case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
32071da177e4SLinus Torvalds 	case SRB_STATUS_DELAYED_RETRY:
32081da177e4SLinus Torvalds 	case SRB_STATUS_BAD_FUNCTION:
32091da177e4SLinus Torvalds 	case SRB_STATUS_NOT_STARTED:
32101da177e4SLinus Torvalds 	case SRB_STATUS_NOT_IN_USE:
32111da177e4SLinus Torvalds 	case SRB_STATUS_FORCE_ABORT:
32121da177e4SLinus Torvalds 	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
32131da177e4SLinus Torvalds 	default:
32141da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
32154ec57fb4SRaghava Aditya Renukunta 		pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n",
32161da177e4SLinus Torvalds 			le32_to_cpu(srbreply->srb_status) & 0x3F,
32171da177e4SLinus Torvalds 			aac_get_status_string(
32181da177e4SLinus Torvalds 				le32_to_cpu(srbreply->srb_status) & 0x3F),
32191da177e4SLinus Torvalds 			scsicmd->cmnd[0],
32201da177e4SLinus Torvalds 			le32_to_cpu(srbreply->scsi_status));
32211da177e4SLinus Torvalds #endif
32224ec57fb4SRaghava Aditya Renukunta 		/*
32234ec57fb4SRaghava Aditya Renukunta 		 * When the CC bit is SET by the host in ATA pass thru CDB,
32244ec57fb4SRaghava Aditya Renukunta 		 *  driver is supposed to return DID_OK
32254ec57fb4SRaghava Aditya Renukunta 		 *
32264ec57fb4SRaghava Aditya Renukunta 		 * When the CC bit is RESET by the host, driver should
32274ec57fb4SRaghava Aditya Renukunta 		 *  return DID_ERROR
32284ec57fb4SRaghava Aditya Renukunta 		 */
32291fc8010aSRajashekhara, Mahesh 		if ((scsicmd->cmnd[0] == ATA_12)
32301fc8010aSRajashekhara, Mahesh 			|| (scsicmd->cmnd[0] == ATA_16)) {
32314ec57fb4SRaghava Aditya Renukunta 
32321fc8010aSRajashekhara, Mahesh 			if (scsicmd->cmnd[2] & (0x01 << 5)) {
32331fc8010aSRajashekhara, Mahesh 				scsicmd->result = DID_OK << 16
32341fc8010aSRajashekhara, Mahesh 					| COMMAND_COMPLETE << 8;
32351da177e4SLinus Torvalds 			break;
32361fc8010aSRajashekhara, Mahesh 			} else {
32371fc8010aSRajashekhara, Mahesh 				scsicmd->result = DID_ERROR << 16
32381fc8010aSRajashekhara, Mahesh 					| COMMAND_COMPLETE << 8;
32391fc8010aSRajashekhara, Mahesh 			break;
32401fc8010aSRajashekhara, Mahesh 			}
32411fc8010aSRajashekhara, Mahesh 		} else {
32421fc8010aSRajashekhara, Mahesh 			scsicmd->result = DID_ERROR << 16
32431fc8010aSRajashekhara, Mahesh 				| COMMAND_COMPLETE << 8;
32441fc8010aSRajashekhara, Mahesh 			break;
32451fc8010aSRajashekhara, Mahesh 		}
32461da177e4SLinus Torvalds 	}
324755b87608SMahesh Rajashekhara 	if (le32_to_cpu(srbreply->scsi_status)
324855b87608SMahesh Rajashekhara 			== SAM_STAT_CHECK_CONDITION) {
32491da177e4SLinus Torvalds 		int len;
325055b87608SMahesh Rajashekhara 
32511da177e4SLinus Torvalds 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
32523ace426fSSalyzyn, Mark 		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
32533ace426fSSalyzyn, Mark 			    SCSI_SENSE_BUFFERSIZE);
32541da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
32554ec57fb4SRaghava Aditya Renukunta 		pr_warn("aac_srb_callback: check condition, status = %d len=%d\n",
32567a8cf29dSMark Haverkamp 					le32_to_cpu(srbreply->status), len);
32571da177e4SLinus Torvalds #endif
325855b87608SMahesh Rajashekhara 		memcpy(scsicmd->sense_buffer,
325955b87608SMahesh Rajashekhara 				srbreply->sense_data, len);
326055b87608SMahesh Rajashekhara 	}
32614ec57fb4SRaghava Aditya Renukunta 
32621da177e4SLinus Torvalds 	/*
32631da177e4SLinus Torvalds 	 * OR in the scsi status (already shifted up a bit)
32641da177e4SLinus Torvalds 	 */
32651da177e4SLinus Torvalds 	scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
32661da177e4SLinus Torvalds 
3267bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
32688e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
32691da177e4SLinus Torvalds }
32701da177e4SLinus Torvalds 
32711da177e4SLinus Torvalds /**
32721da177e4SLinus Torvalds  *
32731da177e4SLinus Torvalds  * aac_send_scb_fib
32741da177e4SLinus Torvalds  * @scsicmd: the scsi command block
32751da177e4SLinus Torvalds  *
32761da177e4SLinus Torvalds  * This routine will form a FIB and fill in the aac_srb from the
32771da177e4SLinus Torvalds  * scsicmd passed in.
32781da177e4SLinus Torvalds  */
32791da177e4SLinus Torvalds 
32801da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
32811da177e4SLinus Torvalds {
32821da177e4SLinus Torvalds 	struct fib* cmd_fibcontext;
32831da177e4SLinus Torvalds 	struct aac_dev* dev;
32841da177e4SLinus Torvalds 	int status;
32851da177e4SLinus Torvalds 
328684971738SMark Haverkamp 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
3287e5718774SMark Haverkamp 	if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
328884971738SMark Haverkamp 			scsicmd->device->lun > 7) {
32891da177e4SLinus Torvalds 		scsicmd->result = DID_NO_CONNECT << 16;
32901da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
32911da177e4SLinus Torvalds 		return 0;
32921da177e4SLinus Torvalds 	}
32931da177e4SLinus Torvalds 
32941da177e4SLinus Torvalds 	/*
32951da177e4SLinus Torvalds 	 *	Allocate and initialize a Fib then setup a BlockWrite command
32961da177e4SLinus Torvalds 	 */
32976bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
32986bf3b630SRaghava Aditya Renukunta 
3299e8f32de5SMark Haverkamp 	status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
33001da177e4SLinus Torvalds 
33011da177e4SLinus Torvalds 	/*
33021da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
33031da177e4SLinus Torvalds 	 */
33041da177e4SLinus Torvalds 	if (status == -EINPROGRESS) {
330577d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
33061da177e4SLinus Torvalds 		return 0;
33071da177e4SLinus Torvalds 	}
33081da177e4SLinus Torvalds 
3309bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
3310bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
3311bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
33121da177e4SLinus Torvalds 
33131da177e4SLinus Torvalds 	return -1;
33141da177e4SLinus Torvalds }
33151da177e4SLinus Torvalds 
33160b433447SMahesh Rajashekhara static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
33171da177e4SLinus Torvalds {
33181da177e4SLinus Torvalds 	struct aac_dev *dev;
33191da177e4SLinus Torvalds 	unsigned long byte_count = 0;
3320727eead6SFUJITA Tomonori 	int nseg;
33211da177e4SLinus Torvalds 
33221da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
33231da177e4SLinus Torvalds 	// Get rid of old data
33241da177e4SLinus Torvalds 	psg->count = 0;
33251da177e4SLinus Torvalds 	psg->sg[0].addr = 0;
33261da177e4SLinus Torvalds 	psg->sg[0].count = 0;
3327727eead6SFUJITA Tomonori 
3328727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
33290b433447SMahesh Rajashekhara 	if (nseg < 0)
33300b433447SMahesh Rajashekhara 		return nseg;
3331727eead6SFUJITA Tomonori 	if (nseg) {
33321da177e4SLinus Torvalds 		struct scatterlist *sg;
33331da177e4SLinus Torvalds 		int i;
33341da177e4SLinus Torvalds 
3335727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
33361da177e4SLinus Torvalds 
3337727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
33381da177e4SLinus Torvalds 			psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
33391da177e4SLinus Torvalds 			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
33401da177e4SLinus Torvalds 			byte_count += sg_dma_len(sg);
33411da177e4SLinus Torvalds 		}
33421da177e4SLinus Torvalds 		/* hba wants the size to be exact */
3343727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
334456b58712SMark Haverkamp  			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
3345727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
334656b58712SMark Haverkamp  			psg->sg[i-1].count = cpu_to_le32(temp);
3347727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
33481da177e4SLinus Torvalds 		}
33491da177e4SLinus Torvalds 		/* Check for command underflow */
33501da177e4SLinus Torvalds 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
33511da177e4SLinus Torvalds 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
33521da177e4SLinus Torvalds 					byte_count, scsicmd->underflow);
33531da177e4SLinus Torvalds 		}
33541da177e4SLinus Torvalds 	}
33551da177e4SLinus Torvalds 	return byte_count;
33561da177e4SLinus Torvalds }
33571da177e4SLinus Torvalds 
33581da177e4SLinus Torvalds 
33590b433447SMahesh Rajashekhara static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg)
33601da177e4SLinus Torvalds {
33611da177e4SLinus Torvalds 	struct aac_dev *dev;
33621da177e4SLinus Torvalds 	unsigned long byte_count = 0;
336356b58712SMark Haverkamp  	u64 addr;
3364727eead6SFUJITA Tomonori 	int nseg;
33651da177e4SLinus Torvalds 
33661da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
33671da177e4SLinus Torvalds 	// Get rid of old data
33681da177e4SLinus Torvalds 	psg->count = 0;
33691da177e4SLinus Torvalds 	psg->sg[0].addr[0] = 0;
33701da177e4SLinus Torvalds 	psg->sg[0].addr[1] = 0;
33711da177e4SLinus Torvalds 	psg->sg[0].count = 0;
3372727eead6SFUJITA Tomonori 
3373727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
33740b433447SMahesh Rajashekhara 	if (nseg < 0)
33750b433447SMahesh Rajashekhara 		return nseg;
3376727eead6SFUJITA Tomonori 	if (nseg) {
33771da177e4SLinus Torvalds 		struct scatterlist *sg;
33781da177e4SLinus Torvalds 		int i;
33791da177e4SLinus Torvalds 
3380727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
33811241f359SMark Haverkamp 			int count = sg_dma_len(sg);
338256b58712SMark Haverkamp  			addr = sg_dma_address(sg);
338356b58712SMark Haverkamp  			psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
338456b58712SMark Haverkamp  			psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
33851241f359SMark Haverkamp 			psg->sg[i].count = cpu_to_le32(count);
33861241f359SMark Haverkamp 			byte_count += count;
33871da177e4SLinus Torvalds 		}
3388727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
33891da177e4SLinus Torvalds 		/* hba wants the size to be exact */
3390727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
339156b58712SMark Haverkamp  			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
3392727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
339356b58712SMark Haverkamp  			psg->sg[i-1].count = cpu_to_le32(temp);
3394727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
33951da177e4SLinus Torvalds 		}
33961da177e4SLinus Torvalds 		/* Check for command underflow */
33971da177e4SLinus Torvalds 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
33981da177e4SLinus Torvalds 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
33991da177e4SLinus Torvalds 					byte_count, scsicmd->underflow);
34001da177e4SLinus Torvalds 		}
34011da177e4SLinus Torvalds 	}
34021da177e4SLinus Torvalds 	return byte_count;
34031da177e4SLinus Torvalds }
34041da177e4SLinus Torvalds 
34050b433447SMahesh Rajashekhara static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg)
34060e68c003SMark Haverkamp {
34070e68c003SMark Haverkamp 	unsigned long byte_count = 0;
3408727eead6SFUJITA Tomonori 	int nseg;
34090e68c003SMark Haverkamp 
34100e68c003SMark Haverkamp 	// Get rid of old data
34110e68c003SMark Haverkamp 	psg->count = 0;
34120e68c003SMark Haverkamp 	psg->sg[0].next = 0;
34130e68c003SMark Haverkamp 	psg->sg[0].prev = 0;
34140e68c003SMark Haverkamp 	psg->sg[0].addr[0] = 0;
34150e68c003SMark Haverkamp 	psg->sg[0].addr[1] = 0;
34160e68c003SMark Haverkamp 	psg->sg[0].count = 0;
34170e68c003SMark Haverkamp 	psg->sg[0].flags = 0;
3418727eead6SFUJITA Tomonori 
3419727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
34200b433447SMahesh Rajashekhara 	if (nseg < 0)
34210b433447SMahesh Rajashekhara 		return nseg;
3422727eead6SFUJITA Tomonori 	if (nseg) {
34230e68c003SMark Haverkamp 		struct scatterlist *sg;
34240e68c003SMark Haverkamp 		int i;
34250e68c003SMark Haverkamp 
3426727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
34270e68c003SMark Haverkamp 			int count = sg_dma_len(sg);
34280e68c003SMark Haverkamp 			u64 addr = sg_dma_address(sg);
34290e68c003SMark Haverkamp 			psg->sg[i].next = 0;
34300e68c003SMark Haverkamp 			psg->sg[i].prev = 0;
34310e68c003SMark Haverkamp 			psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
34320e68c003SMark Haverkamp 			psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
34330e68c003SMark Haverkamp 			psg->sg[i].count = cpu_to_le32(count);
34340e68c003SMark Haverkamp 			psg->sg[i].flags = 0;
34350e68c003SMark Haverkamp 			byte_count += count;
34360e68c003SMark Haverkamp 		}
3437727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
34380e68c003SMark Haverkamp 		/* hba wants the size to be exact */
3439727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
34400e68c003SMark Haverkamp 			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
3441727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
34420e68c003SMark Haverkamp 			psg->sg[i-1].count = cpu_to_le32(temp);
3443727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
34440e68c003SMark Haverkamp 		}
34450e68c003SMark Haverkamp 		/* Check for command underflow */
34460e68c003SMark Haverkamp 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
34470e68c003SMark Haverkamp 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
34480e68c003SMark Haverkamp 					byte_count, scsicmd->underflow);
34490e68c003SMark Haverkamp 		}
34500e68c003SMark Haverkamp 	}
34510e68c003SMark Haverkamp 	return byte_count;
34520e68c003SMark Haverkamp }
34530e68c003SMark Haverkamp 
34540b433447SMahesh Rajashekhara static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
34550b433447SMahesh Rajashekhara 				struct aac_raw_io2 *rio2, int sg_max)
345685d22bbfSMahesh Rajashekhara {
345785d22bbfSMahesh Rajashekhara 	unsigned long byte_count = 0;
345885d22bbfSMahesh Rajashekhara 	int nseg;
345985d22bbfSMahesh Rajashekhara 
346085d22bbfSMahesh Rajashekhara 	nseg = scsi_dma_map(scsicmd);
34610b433447SMahesh Rajashekhara 	if (nseg < 0)
34620b433447SMahesh Rajashekhara 		return nseg;
346385d22bbfSMahesh Rajashekhara 	if (nseg) {
346485d22bbfSMahesh Rajashekhara 		struct scatterlist *sg;
346585d22bbfSMahesh Rajashekhara 		int i, conformable = 0;
346685d22bbfSMahesh Rajashekhara 		u32 min_size = PAGE_SIZE, cur_size;
346785d22bbfSMahesh Rajashekhara 
346885d22bbfSMahesh Rajashekhara 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
346985d22bbfSMahesh Rajashekhara 			int count = sg_dma_len(sg);
347085d22bbfSMahesh Rajashekhara 			u64 addr = sg_dma_address(sg);
347185d22bbfSMahesh Rajashekhara 
347285d22bbfSMahesh Rajashekhara 			BUG_ON(i >= sg_max);
347385d22bbfSMahesh Rajashekhara 			rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32));
347485d22bbfSMahesh Rajashekhara 			rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff));
347585d22bbfSMahesh Rajashekhara 			cur_size = cpu_to_le32(count);
347685d22bbfSMahesh Rajashekhara 			rio2->sge[i].length = cur_size;
347785d22bbfSMahesh Rajashekhara 			rio2->sge[i].flags = 0;
347885d22bbfSMahesh Rajashekhara 			if (i == 0) {
347985d22bbfSMahesh Rajashekhara 				conformable = 1;
348085d22bbfSMahesh Rajashekhara 				rio2->sgeFirstSize = cur_size;
348185d22bbfSMahesh Rajashekhara 			} else if (i == 1) {
348285d22bbfSMahesh Rajashekhara 				rio2->sgeNominalSize = cur_size;
348385d22bbfSMahesh Rajashekhara 				min_size = cur_size;
348485d22bbfSMahesh Rajashekhara 			} else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) {
348585d22bbfSMahesh Rajashekhara 				conformable = 0;
348685d22bbfSMahesh Rajashekhara 				if (cur_size < min_size)
348785d22bbfSMahesh Rajashekhara 					min_size = cur_size;
348885d22bbfSMahesh Rajashekhara 			}
348985d22bbfSMahesh Rajashekhara 			byte_count += count;
349085d22bbfSMahesh Rajashekhara 		}
349185d22bbfSMahesh Rajashekhara 
349285d22bbfSMahesh Rajashekhara 		/* hba wants the size to be exact */
349385d22bbfSMahesh Rajashekhara 		if (byte_count > scsi_bufflen(scsicmd)) {
349485d22bbfSMahesh Rajashekhara 			u32 temp = le32_to_cpu(rio2->sge[i-1].length) -
349585d22bbfSMahesh Rajashekhara 				(byte_count - scsi_bufflen(scsicmd));
349685d22bbfSMahesh Rajashekhara 			rio2->sge[i-1].length = cpu_to_le32(temp);
349785d22bbfSMahesh Rajashekhara 			byte_count = scsi_bufflen(scsicmd);
349885d22bbfSMahesh Rajashekhara 		}
349985d22bbfSMahesh Rajashekhara 
350085d22bbfSMahesh Rajashekhara 		rio2->sgeCnt = cpu_to_le32(nseg);
350185d22bbfSMahesh Rajashekhara 		rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212);
350285d22bbfSMahesh Rajashekhara 		/* not conformable: evaluate required sg elements */
350385d22bbfSMahesh Rajashekhara 		if (!conformable) {
350485d22bbfSMahesh Rajashekhara 			int j, nseg_new = nseg, err_found;
350585d22bbfSMahesh Rajashekhara 			for (i = min_size / PAGE_SIZE; i >= 1; --i) {
350685d22bbfSMahesh Rajashekhara 				err_found = 0;
350785d22bbfSMahesh Rajashekhara 				nseg_new = 2;
350885d22bbfSMahesh Rajashekhara 				for (j = 1; j < nseg - 1; ++j) {
350985d22bbfSMahesh Rajashekhara 					if (rio2->sge[j].length % (i*PAGE_SIZE)) {
351085d22bbfSMahesh Rajashekhara 						err_found = 1;
351185d22bbfSMahesh Rajashekhara 						break;
351285d22bbfSMahesh Rajashekhara 					}
351385d22bbfSMahesh Rajashekhara 					nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE));
351485d22bbfSMahesh Rajashekhara 				}
351585d22bbfSMahesh Rajashekhara 				if (!err_found)
351685d22bbfSMahesh Rajashekhara 					break;
351785d22bbfSMahesh Rajashekhara 			}
351885d22bbfSMahesh Rajashekhara 			if (i > 0 && nseg_new <= sg_max)
351985d22bbfSMahesh Rajashekhara 				aac_convert_sgraw2(rio2, i, nseg, nseg_new);
352085d22bbfSMahesh Rajashekhara 		} else
352185d22bbfSMahesh Rajashekhara 			rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT);
352285d22bbfSMahesh Rajashekhara 
352385d22bbfSMahesh Rajashekhara 		/* Check for command underflow */
352485d22bbfSMahesh Rajashekhara 		if (scsicmd->underflow && (byte_count < scsicmd->underflow)) {
352585d22bbfSMahesh Rajashekhara 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
352685d22bbfSMahesh Rajashekhara 					byte_count, scsicmd->underflow);
352785d22bbfSMahesh Rajashekhara 		}
352885d22bbfSMahesh Rajashekhara 	}
352985d22bbfSMahesh Rajashekhara 
353085d22bbfSMahesh Rajashekhara 	return byte_count;
353185d22bbfSMahesh Rajashekhara }
353285d22bbfSMahesh Rajashekhara 
353385d22bbfSMahesh Rajashekhara static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new)
353485d22bbfSMahesh Rajashekhara {
353585d22bbfSMahesh Rajashekhara 	struct sge_ieee1212 *sge;
353685d22bbfSMahesh Rajashekhara 	int i, j, pos;
353785d22bbfSMahesh Rajashekhara 	u32 addr_low;
353885d22bbfSMahesh Rajashekhara 
353985d22bbfSMahesh Rajashekhara 	if (aac_convert_sgl == 0)
354085d22bbfSMahesh Rajashekhara 		return 0;
354185d22bbfSMahesh Rajashekhara 
354285d22bbfSMahesh Rajashekhara 	sge = kmalloc(nseg_new * sizeof(struct sge_ieee1212), GFP_ATOMIC);
354385d22bbfSMahesh Rajashekhara 	if (sge == NULL)
354485d22bbfSMahesh Rajashekhara 		return -1;
354585d22bbfSMahesh Rajashekhara 
354685d22bbfSMahesh Rajashekhara 	for (i = 1, pos = 1; i < nseg-1; ++i) {
354785d22bbfSMahesh Rajashekhara 		for (j = 0; j < rio2->sge[i].length / (pages * PAGE_SIZE); ++j) {
354885d22bbfSMahesh Rajashekhara 			addr_low = rio2->sge[i].addrLow + j * pages * PAGE_SIZE;
354985d22bbfSMahesh Rajashekhara 			sge[pos].addrLow = addr_low;
355085d22bbfSMahesh Rajashekhara 			sge[pos].addrHigh = rio2->sge[i].addrHigh;
355185d22bbfSMahesh Rajashekhara 			if (addr_low < rio2->sge[i].addrLow)
355285d22bbfSMahesh Rajashekhara 				sge[pos].addrHigh++;
355385d22bbfSMahesh Rajashekhara 			sge[pos].length = pages * PAGE_SIZE;
355485d22bbfSMahesh Rajashekhara 			sge[pos].flags = 0;
355585d22bbfSMahesh Rajashekhara 			pos++;
355685d22bbfSMahesh Rajashekhara 		}
355785d22bbfSMahesh Rajashekhara 	}
355885d22bbfSMahesh Rajashekhara 	sge[pos] = rio2->sge[nseg-1];
355985d22bbfSMahesh Rajashekhara 	memcpy(&rio2->sge[1], &sge[1], (nseg_new-1)*sizeof(struct sge_ieee1212));
356085d22bbfSMahesh Rajashekhara 
356185d22bbfSMahesh Rajashekhara 	kfree(sge);
356285d22bbfSMahesh Rajashekhara 	rio2->sgeCnt = cpu_to_le32(nseg_new);
356385d22bbfSMahesh Rajashekhara 	rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT);
356485d22bbfSMahesh Rajashekhara 	rio2->sgeNominalSize = pages * PAGE_SIZE;
356585d22bbfSMahesh Rajashekhara 	return 0;
356685d22bbfSMahesh Rajashekhara }
356785d22bbfSMahesh Rajashekhara 
35681da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
35691da177e4SLinus Torvalds 
35701da177e4SLinus Torvalds struct aac_srb_status_info {
35711da177e4SLinus Torvalds 	u32	status;
35721da177e4SLinus Torvalds 	char	*str;
35731da177e4SLinus Torvalds };
35741da177e4SLinus Torvalds 
35751da177e4SLinus Torvalds 
35761da177e4SLinus Torvalds static struct aac_srb_status_info srb_status_info[] = {
35771da177e4SLinus Torvalds 	{ SRB_STATUS_PENDING,		"Pending Status"},
35781da177e4SLinus Torvalds 	{ SRB_STATUS_SUCCESS,		"Success"},
35791da177e4SLinus Torvalds 	{ SRB_STATUS_ABORTED,		"Aborted Command"},
35801da177e4SLinus Torvalds 	{ SRB_STATUS_ABORT_FAILED,	"Abort Failed"},
35811da177e4SLinus Torvalds 	{ SRB_STATUS_ERROR,		"Error Event"},
35821da177e4SLinus Torvalds 	{ SRB_STATUS_BUSY,		"Device Busy"},
35831da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_REQUEST,	"Invalid Request"},
35841da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_PATH_ID,	"Invalid Path ID"},
35851da177e4SLinus Torvalds 	{ SRB_STATUS_NO_DEVICE,		"No Device"},
35861da177e4SLinus Torvalds 	{ SRB_STATUS_TIMEOUT,		"Timeout"},
35871da177e4SLinus Torvalds 	{ SRB_STATUS_SELECTION_TIMEOUT,	"Selection Timeout"},
35881da177e4SLinus Torvalds 	{ SRB_STATUS_COMMAND_TIMEOUT,	"Command Timeout"},
35891da177e4SLinus Torvalds 	{ SRB_STATUS_MESSAGE_REJECTED,	"Message Rejected"},
35901da177e4SLinus Torvalds 	{ SRB_STATUS_BUS_RESET,		"Bus Reset"},
35911da177e4SLinus Torvalds 	{ SRB_STATUS_PARITY_ERROR,	"Parity Error"},
35921da177e4SLinus Torvalds 	{ SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"},
35931da177e4SLinus Torvalds 	{ SRB_STATUS_NO_HBA,		"No HBA"},
35941da177e4SLinus Torvalds 	{ SRB_STATUS_DATA_OVERRUN,	"Data Overrun/Data Underrun"},
35951da177e4SLinus Torvalds 	{ SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"},
35961da177e4SLinus Torvalds 	{ SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"},
35971da177e4SLinus Torvalds 	{ SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
35981da177e4SLinus Torvalds 	{ SRB_STATUS_REQUEST_FLUSHED,	"Request Flushed"},
35991da177e4SLinus Torvalds 	{ SRB_STATUS_DELAYED_RETRY,	"Delayed Retry"},
36001da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_LUN,	"Invalid LUN"},
36011da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_TARGET_ID,	"Invalid TARGET ID"},
36021da177e4SLinus Torvalds 	{ SRB_STATUS_BAD_FUNCTION,	"Bad Function"},
36031da177e4SLinus Torvalds 	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
36041da177e4SLinus Torvalds 	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
36051da177e4SLinus Torvalds 	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
36061da177e4SLinus Torvalds 	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
36071da177e4SLinus Torvalds 	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
36081da177e4SLinus Torvalds 	{ 0xff,				"Unknown Error"}
36091da177e4SLinus Torvalds };
36101da177e4SLinus Torvalds 
36111da177e4SLinus Torvalds char *aac_get_status_string(u32 status)
36121da177e4SLinus Torvalds {
36131da177e4SLinus Torvalds 	int i;
36141da177e4SLinus Torvalds 
36156391a113STobias Klauser 	for (i = 0; i < ARRAY_SIZE(srb_status_info); i++)
36166391a113STobias Klauser 		if (srb_status_info[i].status == status)
36171da177e4SLinus Torvalds 			return srb_status_info[i].str;
36181da177e4SLinus Torvalds 
36191da177e4SLinus Torvalds 	return "Bad Status Code";
36201da177e4SLinus Torvalds }
36211da177e4SLinus Torvalds 
36221da177e4SLinus Torvalds #endif
3623