xref: /openbmc/linux/drivers/scsi/aacraid/aachba.c (revision ab5d129f)
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
65f956a669SRaghava Aditya Renukunta #define SENCODE_UNRECOVERED_READ_ERROR		0x11
661da177e4SLinus Torvalds #define SENCODE_PARAM_LIST_LENGTH_ERROR		0x1A
671da177e4SLinus Torvalds #define SENCODE_INVALID_COMMAND			0x20
681da177e4SLinus Torvalds #define SENCODE_LBA_OUT_OF_RANGE		0x21
691da177e4SLinus Torvalds #define SENCODE_INVALID_CDB_FIELD		0x24
701da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SUPPORTED		0x25
711da177e4SLinus Torvalds #define SENCODE_INVALID_PARAM_FIELD		0x26
721da177e4SLinus Torvalds #define SENCODE_PARAM_NOT_SUPPORTED		0x26
731da177e4SLinus Torvalds #define SENCODE_PARAM_VALUE_INVALID		0x26
741da177e4SLinus Torvalds #define SENCODE_RESET_OCCURRED			0x29
751da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x3E
761da177e4SLinus Torvalds #define SENCODE_INQUIRY_DATA_CHANGED		0x3F
771da177e4SLinus Torvalds #define SENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x39
781da177e4SLinus Torvalds #define SENCODE_DIAGNOSTIC_FAILURE		0x40
791da177e4SLinus Torvalds #define SENCODE_INTERNAL_TARGET_FAILURE		0x44
801da177e4SLinus Torvalds #define SENCODE_INVALID_MESSAGE_ERROR		0x49
811da177e4SLinus Torvalds #define SENCODE_LUN_FAILED_SELF_CONFIG		0x4c
821da177e4SLinus Torvalds #define SENCODE_OVERLAPPED_COMMAND		0x4E
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds /*
851da177e4SLinus Torvalds  *	Additional sense codes
861da177e4SLinus Torvalds  */
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds #define ASENCODE_NO_SENSE			0x00
891da177e4SLinus Torvalds #define ASENCODE_END_OF_DATA			0x05
901da177e4SLinus Torvalds #define ASENCODE_BECOMING_READY			0x01
911da177e4SLinus Torvalds #define ASENCODE_INIT_CMD_REQUIRED		0x02
921da177e4SLinus Torvalds #define ASENCODE_PARAM_LIST_LENGTH_ERROR	0x00
931da177e4SLinus Torvalds #define ASENCODE_INVALID_COMMAND		0x00
941da177e4SLinus Torvalds #define ASENCODE_LBA_OUT_OF_RANGE		0x00
951da177e4SLinus Torvalds #define ASENCODE_INVALID_CDB_FIELD		0x00
961da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SUPPORTED		0x00
971da177e4SLinus Torvalds #define ASENCODE_INVALID_PARAM_FIELD		0x00
981da177e4SLinus Torvalds #define ASENCODE_PARAM_NOT_SUPPORTED		0x01
991da177e4SLinus Torvalds #define ASENCODE_PARAM_VALUE_INVALID		0x02
1001da177e4SLinus Torvalds #define ASENCODE_RESET_OCCURRED			0x00
1011da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x00
1021da177e4SLinus Torvalds #define ASENCODE_INQUIRY_DATA_CHANGED		0x03
1031da177e4SLinus Torvalds #define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x00
1041da177e4SLinus Torvalds #define ASENCODE_DIAGNOSTIC_FAILURE		0x80
1051da177e4SLinus Torvalds #define ASENCODE_INTERNAL_TARGET_FAILURE	0x00
1061da177e4SLinus Torvalds #define ASENCODE_INVALID_MESSAGE_ERROR		0x00
1071da177e4SLinus Torvalds #define ASENCODE_LUN_FAILED_SELF_CONFIG		0x00
1081da177e4SLinus Torvalds #define ASENCODE_OVERLAPPED_COMMAND		0x00
1091da177e4SLinus Torvalds 
110c4e2fbcaSRaghava Aditya Renukunta #define AAC_STAT_GOOD (DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD)
111c4e2fbcaSRaghava Aditya Renukunta 
1121da177e4SLinus Torvalds #define BYTE0(x) (unsigned char)(x)
1131da177e4SLinus Torvalds #define BYTE1(x) (unsigned char)((x) >> 8)
1141da177e4SLinus Torvalds #define BYTE2(x) (unsigned char)((x) >> 16)
1151da177e4SLinus Torvalds #define BYTE3(x) (unsigned char)((x) >> 24)
1161da177e4SLinus Torvalds 
117b836439fSMahesh Rajashekhara /* MODE_SENSE data format */
118b836439fSMahesh Rajashekhara typedef struct {
119b836439fSMahesh Rajashekhara 	struct {
120b836439fSMahesh Rajashekhara 		u8	data_length;
121b836439fSMahesh Rajashekhara 		u8	med_type;
122b836439fSMahesh Rajashekhara 		u8	dev_par;
123b836439fSMahesh Rajashekhara 		u8	bd_length;
124b836439fSMahesh Rajashekhara 	} __attribute__((packed)) hd;
125b836439fSMahesh Rajashekhara 	struct {
126b836439fSMahesh Rajashekhara 		u8	dens_code;
127b836439fSMahesh Rajashekhara 		u8	block_count[3];
128b836439fSMahesh Rajashekhara 		u8	reserved;
129b836439fSMahesh Rajashekhara 		u8	block_length[3];
130b836439fSMahesh Rajashekhara 	} __attribute__((packed)) bd;
131b836439fSMahesh Rajashekhara 		u8	mpc_buf[3];
132b836439fSMahesh Rajashekhara } __attribute__((packed)) aac_modep_data;
133b836439fSMahesh Rajashekhara 
134b836439fSMahesh Rajashekhara /* MODE_SENSE_10 data format */
135b836439fSMahesh Rajashekhara typedef struct {
136b836439fSMahesh Rajashekhara 	struct {
137b836439fSMahesh Rajashekhara 		u8	data_length[2];
138b836439fSMahesh Rajashekhara 		u8	med_type;
139b836439fSMahesh Rajashekhara 		u8	dev_par;
140b836439fSMahesh Rajashekhara 		u8	rsrvd[2];
141b836439fSMahesh Rajashekhara 		u8	bd_length[2];
142b836439fSMahesh Rajashekhara 	} __attribute__((packed)) hd;
143b836439fSMahesh Rajashekhara 	struct {
144b836439fSMahesh Rajashekhara 		u8	dens_code;
145b836439fSMahesh Rajashekhara 		u8	block_count[3];
146b836439fSMahesh Rajashekhara 		u8	reserved;
147b836439fSMahesh Rajashekhara 		u8	block_length[3];
148b836439fSMahesh Rajashekhara 	} __attribute__((packed)) bd;
149b836439fSMahesh Rajashekhara 		u8	mpc_buf[3];
150b836439fSMahesh Rajashekhara } __attribute__((packed)) aac_modep10_data;
151b836439fSMahesh Rajashekhara 
1521da177e4SLinus Torvalds /*------------------------------------------------------------------------------
1531da177e4SLinus Torvalds  *              S T R U C T S / T Y P E D E F S
1541da177e4SLinus Torvalds  *----------------------------------------------------------------------------*/
1551da177e4SLinus Torvalds /* SCSI inquiry data */
1561da177e4SLinus Torvalds struct inquiry_data {
1571da177e4SLinus Torvalds 	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type */
1581da177e4SLinus Torvalds 	u8 inqd_dtq;	/* RMB | Device Type Qualifier */
1591da177e4SLinus Torvalds 	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
1601da177e4SLinus Torvalds 	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
1611da177e4SLinus Torvalds 	u8 inqd_len;	/* Additional length (n-4) */
1621da177e4SLinus Torvalds 	u8 inqd_pad1[2];/* Reserved - must be zero */
1631da177e4SLinus Torvalds 	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
1641da177e4SLinus Torvalds 	u8 inqd_vid[8];	/* Vendor ID */
1651da177e4SLinus Torvalds 	u8 inqd_pid[16];/* Product ID */
1661da177e4SLinus Torvalds 	u8 inqd_prl[4];	/* Product Revision Level */
1671da177e4SLinus Torvalds };
1681da177e4SLinus Torvalds 
1695d910649SMahesh Rajashekhara /* Added for VPD 0x83 */
1705d910649SMahesh Rajashekhara typedef struct {
1715d910649SMahesh Rajashekhara 	u8 CodeSet:4;	/* VPD_CODE_SET */
1725d910649SMahesh Rajashekhara 	u8 Reserved:4;
1735d910649SMahesh Rajashekhara 	u8 IdentifierType:4;	/* VPD_IDENTIFIER_TYPE */
1745d910649SMahesh Rajashekhara 	u8 Reserved2:4;
1755d910649SMahesh Rajashekhara 	u8 Reserved3;
1765d910649SMahesh Rajashekhara 	u8 IdentifierLength;
1775d910649SMahesh Rajashekhara 	u8 VendId[8];
1785d910649SMahesh Rajashekhara 	u8 ProductId[16];
1795d910649SMahesh Rajashekhara 	u8 SerialNumber[8];	/* SN in ASCII */
1805d910649SMahesh Rajashekhara 
1815d910649SMahesh Rajashekhara } TVPD_ID_Descriptor_Type_1;
1825d910649SMahesh Rajashekhara 
1835d910649SMahesh Rajashekhara typedef struct {
1845d910649SMahesh Rajashekhara 	u8 CodeSet:4;	/* VPD_CODE_SET */
1855d910649SMahesh Rajashekhara 	u8 Reserved:4;
1865d910649SMahesh Rajashekhara 	u8 IdentifierType:4;	/* VPD_IDENTIFIER_TYPE */
1875d910649SMahesh Rajashekhara 	u8 Reserved2:4;
1885d910649SMahesh Rajashekhara 	u8 Reserved3;
1895d910649SMahesh Rajashekhara 	u8 IdentifierLength;
1905d910649SMahesh Rajashekhara 	struct TEU64Id {
1915d910649SMahesh Rajashekhara 		u32 Serial;
1925d910649SMahesh Rajashekhara 		 /* The serial number supposed to be 40 bits,
1935d910649SMahesh Rajashekhara 		  * bit we only support 32, so make the last byte zero. */
1945d910649SMahesh Rajashekhara 		u8 Reserved;
1955d910649SMahesh Rajashekhara 		u8 VendId[3];
1965d910649SMahesh Rajashekhara 	} EU64Id;
1975d910649SMahesh Rajashekhara 
1985d910649SMahesh Rajashekhara } TVPD_ID_Descriptor_Type_2;
1995d910649SMahesh Rajashekhara 
2005d910649SMahesh Rajashekhara typedef struct {
2015d910649SMahesh Rajashekhara 	u8 DeviceType:5;
2025d910649SMahesh Rajashekhara 	u8 DeviceTypeQualifier:3;
2035d910649SMahesh Rajashekhara 	u8 PageCode;
2045d910649SMahesh Rajashekhara 	u8 Reserved;
2055d910649SMahesh Rajashekhara 	u8 PageLength;
2065d910649SMahesh Rajashekhara 	TVPD_ID_Descriptor_Type_1 IdDescriptorType1;
2075d910649SMahesh Rajashekhara 	TVPD_ID_Descriptor_Type_2 IdDescriptorType2;
2085d910649SMahesh Rajashekhara 
2095d910649SMahesh Rajashekhara } TVPD_Page83;
2105d910649SMahesh Rajashekhara 
2111da177e4SLinus Torvalds /*
2121da177e4SLinus Torvalds  *              M O D U L E   G L O B A L S
2131da177e4SLinus Torvalds  */
2141da177e4SLinus Torvalds 
2150b433447SMahesh Rajashekhara static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *sgmap);
2160b433447SMahesh Rajashekhara static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg);
2170b433447SMahesh Rajashekhara static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg);
2180b433447SMahesh Rajashekhara static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
2190b433447SMahesh Rajashekhara 				struct aac_raw_io2 *rio2, int sg_max);
220ab5d129fSRaghava Aditya Renukunta static long aac_build_sghba(struct scsi_cmnd *scsicmd,
221ab5d129fSRaghava Aditya Renukunta 				struct aac_hba_cmd_req *hbacmd,
222ab5d129fSRaghava Aditya Renukunta 				int sg_max, u64 sg_address);
2230b433447SMahesh Rajashekhara static int aac_convert_sgraw2(struct aac_raw_io2 *rio2,
2240b433447SMahesh Rajashekhara 				int pages, int nseg, int nseg_new);
2251da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
226ab5d129fSRaghava Aditya Renukunta static int aac_send_hba_fib(struct scsi_cmnd *scsicmd);
2271da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
2281da177e4SLinus Torvalds static char *aac_get_status_string(u32 status);
2291da177e4SLinus Torvalds #endif
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds /*
2321da177e4SLinus Torvalds  *	Non dasd selection is handled entirely in aachba now
2331da177e4SLinus Torvalds  */
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds static int nondasd = -1;
236d8e96507SLeubner, Achim static int aac_cache = 2;	/* WCE=0 to avoid performance problems */
2371da177e4SLinus Torvalds static int dacmode = -1;
2388ef22247SSalyzyn, Mark int aac_msi;
2391208bab5SSalyzyn, Mark int aac_commit = -1;
240404d9a90SMark Haverkamp int startup_timeout = 180;
241404d9a90SMark Haverkamp int aif_timeout = 120;
24211604612SMahesh Rajashekhara int aac_sync_mode;  /* Only Sync. transfer - disabled */
24385d22bbfSMahesh Rajashekhara int aac_convert_sgl = 1;	/* convert non-conformable s/g list - enabled */
2441da177e4SLinus Torvalds 
24511604612SMahesh Rajashekhara module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR);
24611604612SMahesh Rajashekhara MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode"
24711604612SMahesh Rajashekhara 	" 0=off, 1=on");
24885d22bbfSMahesh Rajashekhara module_param(aac_convert_sgl, int, S_IRUGO|S_IWUSR);
24985d22bbfSMahesh Rajashekhara MODULE_PARM_DESC(aac_convert_sgl, "Convert non-conformable s/g list"
25085d22bbfSMahesh Rajashekhara 	" 0=off, 1=on");
2519a72f976SMark Haverkamp module_param(nondasd, int, S_IRUGO|S_IWUSR);
2528ef22247SSalyzyn, Mark MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
2538ef22247SSalyzyn, Mark 	" 0=off, 1=on");
25495e852e1SSalyzyn, Mark module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
2558ef22247SSalyzyn, Mark MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n"
2568ef22247SSalyzyn, Mark 	"\tbit 0 - Disable FUA in WRITE SCSI commands\n"
2578ef22247SSalyzyn, Mark 	"\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n"
258d8e96507SLeubner, Achim 	"\tbit 2 - Disable only if Battery is protecting Cache");
2599a72f976SMark Haverkamp module_param(dacmode, int, S_IRUGO|S_IWUSR);
2608ef22247SSalyzyn, Mark MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC."
2618ef22247SSalyzyn, Mark 	" 0=off, 1=on");
2621208bab5SSalyzyn, Mark module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
2638ef22247SSalyzyn, Mark MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
2648ef22247SSalyzyn, Mark 	" adapter for foreign arrays.\n"
2658ef22247SSalyzyn, Mark 	"This is typically needed in systems that do not have a BIOS."
2668ef22247SSalyzyn, Mark 	" 0=off, 1=on");
2678ef22247SSalyzyn, Mark module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
2688ef22247SSalyzyn, Mark MODULE_PARM_DESC(msi, "IRQ handling."
2699022d375SMahesh Rajashekhara 	" 0=PIC(default), 1=MSI, 2=MSI-X)");
270404d9a90SMark Haverkamp module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
2718ef22247SSalyzyn, Mark MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
2728ef22247SSalyzyn, Mark 	" adapter to have it's kernel up and\n"
2738ef22247SSalyzyn, Mark 	"running. This is typically adjusted for large systems that do not"
2748ef22247SSalyzyn, Mark 	" have a BIOS.");
275404d9a90SMark Haverkamp module_param(aif_timeout, int, S_IRUGO|S_IWUSR);
2768ef22247SSalyzyn, Mark MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for"
2778ef22247SSalyzyn, Mark 	" applications to pick up AIFs before\n"
2788ef22247SSalyzyn, Mark 	"deregistering them. This is typically adjusted for heavily burdened"
2798ef22247SSalyzyn, Mark 	" systems.");
2801da177e4SLinus Torvalds 
2817c00ffa3SMark Haverkamp  int numacb = -1;
2827c00ffa3SMark Haverkamp  module_param(numacb, int, S_IRUGO|S_IWUSR);
2838ef22247SSalyzyn, Mark MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control"
2848ef22247SSalyzyn, Mark 	" blocks (FIB) allocated. Valid values are 512 and down. Default is"
2858ef22247SSalyzyn, Mark 	" to use suggestion from Firmware.");
2867c00ffa3SMark Haverkamp  
2877c00ffa3SMark Haverkamp  int acbsize = -1;
2887c00ffa3SMark Haverkamp  module_param(acbsize, int, S_IRUGO|S_IWUSR);
2898ef22247SSalyzyn, Mark MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)"
2908ef22247SSalyzyn, Mark 	" size. Valid values are 512, 2048, 4096 and 8192. Default is to use"
2918ef22247SSalyzyn, Mark 	" suggestion from Firmware.");
292653ba58dSMark Haverkamp 
29329c97684SSalyzyn, Mark int update_interval = 30 * 60;
29429c97684SSalyzyn, Mark module_param(update_interval, int, S_IRUGO|S_IWUSR);
2958ef22247SSalyzyn, Mark MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync"
2968ef22247SSalyzyn, Mark 	" updates issued to adapter.");
29729c97684SSalyzyn, Mark 
29829c97684SSalyzyn, Mark int check_interval = 24 * 60 * 60;
29929c97684SSalyzyn, Mark module_param(check_interval, int, S_IRUGO|S_IWUSR);
3008ef22247SSalyzyn, Mark MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health"
3018ef22247SSalyzyn, Mark 	" checks.");
30229c97684SSalyzyn, Mark 
30387f3bda3SAndrew Morton int aac_check_reset = 1;
30487f3bda3SAndrew Morton module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
30595e7a8efSPaul Bolle MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the"
3068ef22247SSalyzyn, Mark 	" adapter. a value of -1 forces the reset to adapters programmed to"
3078ef22247SSalyzyn, Mark 	" ignore it.");
30829c97684SSalyzyn, Mark 
309e37ee4beSMark Haverkamp int expose_physicals = -1;
310653ba58dSMark Haverkamp module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
3118ef22247SSalyzyn, Mark MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays."
3128ef22247SSalyzyn, Mark 	" -1=protect 0=off, 1=on");
31303d44337SMark Haverkamp 
3148ef22247SSalyzyn, Mark int aac_reset_devices;
3151208bab5SSalyzyn, Mark module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR);
3161208bab5SSalyzyn, Mark MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization.");
31703d44337SMark Haverkamp 
318d8e96507SLeubner, Achim int aac_wwn = 1;
319d8e96507SLeubner, Achim module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR);
320d8e96507SLeubner, Achim MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n"
321d8e96507SLeubner, Achim 	"\t0 - Disable\n"
322d8e96507SLeubner, Achim 	"\t1 - Array Meta Data Signature (default)\n"
323d8e96507SLeubner, Achim 	"\t2 - Adapter Serial Number");
324d8e96507SLeubner, Achim 
325d8e96507SLeubner, Achim 
32603d44337SMark Haverkamp static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
32703d44337SMark Haverkamp 		struct fib *fibptr) {
32803d44337SMark Haverkamp 	struct scsi_device *device;
32903d44337SMark Haverkamp 
33003d44337SMark Haverkamp 	if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
331c835e372SSalyzyn, Mark 		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
33203d44337SMark Haverkamp 		aac_fib_complete(fibptr);
33303d44337SMark Haverkamp 		return 0;
33403d44337SMark Haverkamp 	}
33503d44337SMark Haverkamp 	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
33603d44337SMark Haverkamp 	device = scsicmd->device;
3373ffd6c5aSRaghava Aditya Renukunta 	if (unlikely(!device)) {
33803d44337SMark Haverkamp 		dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
33903d44337SMark Haverkamp 		aac_fib_complete(fibptr);
34003d44337SMark Haverkamp 		return 0;
34103d44337SMark Haverkamp 	}
34203d44337SMark Haverkamp 	return 1;
34303d44337SMark Haverkamp }
34403d44337SMark Haverkamp 
3451da177e4SLinus Torvalds /**
3461da177e4SLinus Torvalds  *	aac_get_config_status	-	check the adapter configuration
3471da177e4SLinus Torvalds  *	@common: adapter to query
3481da177e4SLinus Torvalds  *
3491da177e4SLinus Torvalds  *	Query config status, and commit the configuration if needed.
3501da177e4SLinus Torvalds  */
3518c867b25SMark Haverkamp int aac_get_config_status(struct aac_dev *dev, int commit_flag)
3521da177e4SLinus Torvalds {
3531da177e4SLinus Torvalds 	int status = 0;
3541da177e4SLinus Torvalds 	struct fib * fibptr;
3551da177e4SLinus Torvalds 
356bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
3571da177e4SLinus Torvalds 		return -ENOMEM;
3581da177e4SLinus Torvalds 
359bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
3601da177e4SLinus Torvalds 	{
3611da177e4SLinus Torvalds 		struct aac_get_config_status *dinfo;
3621da177e4SLinus Torvalds 		dinfo = (struct aac_get_config_status *) fib_data(fibptr);
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 		dinfo->command = cpu_to_le32(VM_ContainerConfig);
3651da177e4SLinus Torvalds 		dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
3661da177e4SLinus Torvalds 		dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
3671da177e4SLinus Torvalds 	}
3681da177e4SLinus Torvalds 
369bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
3701da177e4SLinus Torvalds 			    fibptr,
3711da177e4SLinus Torvalds 			    sizeof (struct aac_get_config_status),
3721da177e4SLinus Torvalds 			    FsaNormal,
3731da177e4SLinus Torvalds 			    1, 1,
3741da177e4SLinus Torvalds 			    NULL, NULL);
3751da177e4SLinus Torvalds 	if (status < 0) {
3761da177e4SLinus Torvalds 		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
3771da177e4SLinus Torvalds 	} else {
3781da177e4SLinus Torvalds 		struct aac_get_config_status_resp *reply
3791da177e4SLinus Torvalds 		  = (struct aac_get_config_status_resp *) fib_data(fibptr);
3801da177e4SLinus Torvalds 		dprintk((KERN_WARNING
3811da177e4SLinus Torvalds 		  "aac_get_config_status: response=%d status=%d action=%d\n",
3821da177e4SLinus Torvalds 		  le32_to_cpu(reply->response),
3831da177e4SLinus Torvalds 		  le32_to_cpu(reply->status),
3841da177e4SLinus Torvalds 		  le32_to_cpu(reply->data.action)));
3851da177e4SLinus Torvalds 		if ((le32_to_cpu(reply->response) != ST_OK) ||
3861da177e4SLinus Torvalds 		     (le32_to_cpu(reply->status) != CT_OK) ||
3871da177e4SLinus Torvalds 		     (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
3881da177e4SLinus Torvalds 			printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
3891da177e4SLinus Torvalds 			status = -EINVAL;
3901da177e4SLinus Torvalds 		}
3911da177e4SLinus Torvalds 	}
392cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* Do not set XferState to zero unless receives a response from F/W */
393cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status >= 0)
394bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
395cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
3961da177e4SLinus Torvalds 	/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
3971da177e4SLinus Torvalds 	if (status >= 0) {
3981208bab5SSalyzyn, Mark 		if ((aac_commit == 1) || commit_flag) {
3991da177e4SLinus Torvalds 			struct aac_commit_config * dinfo;
400bfb35aa8SMark Haverkamp 			aac_fib_init(fibptr);
4011da177e4SLinus Torvalds 			dinfo = (struct aac_commit_config *) fib_data(fibptr);
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 			dinfo->command = cpu_to_le32(VM_ContainerConfig);
4041da177e4SLinus Torvalds 			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
4051da177e4SLinus Torvalds 
406bfb35aa8SMark Haverkamp 			status = aac_fib_send(ContainerCommand,
4071da177e4SLinus Torvalds 				    fibptr,
4081da177e4SLinus Torvalds 				    sizeof (struct aac_commit_config),
4091da177e4SLinus Torvalds 				    FsaNormal,
4101da177e4SLinus Torvalds 				    1, 1,
4111da177e4SLinus Torvalds 				    NULL, NULL);
412cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			/* Do not set XferState to zero unless
413cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			 * receives a response from F/W */
414cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			if (status >= 0)
415bfb35aa8SMark Haverkamp 				aac_fib_complete(fibptr);
4161208bab5SSalyzyn, Mark 		} else if (aac_commit == 0) {
4171da177e4SLinus Torvalds 			printk(KERN_WARNING
4181da177e4SLinus Torvalds 			  "aac_get_config_status: Foreign device configurations are being ignored\n");
4191da177e4SLinus Torvalds 		}
4201da177e4SLinus Torvalds 	}
421cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
422cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status != -ERESTARTSYS)
423bfb35aa8SMark Haverkamp 		aac_fib_free(fibptr);
4241da177e4SLinus Torvalds 	return status;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
427e3cc268fSRajashekhara, Mahesh static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
428e3cc268fSRajashekhara, Mahesh {
429e3cc268fSRajashekhara, Mahesh 	char inq_data;
430e3cc268fSRajashekhara, Mahesh 	scsi_sg_copy_to_buffer(scsicmd,  &inq_data, sizeof(inq_data));
431e3cc268fSRajashekhara, Mahesh 	if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
432e3cc268fSRajashekhara, Mahesh 		inq_data &= 0xdf;
433e3cc268fSRajashekhara, Mahesh 		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
434e3cc268fSRajashekhara, Mahesh 	}
435e3cc268fSRajashekhara, Mahesh }
436e3cc268fSRajashekhara, Mahesh 
4371da177e4SLinus Torvalds /**
4381da177e4SLinus Torvalds  *	aac_get_containers	-	list containers
4391da177e4SLinus Torvalds  *	@common: adapter to probe
4401da177e4SLinus Torvalds  *
4411da177e4SLinus Torvalds  *	Make a list of all containers on this controller
4421da177e4SLinus Torvalds  */
4431da177e4SLinus Torvalds int aac_get_containers(struct aac_dev *dev)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
4461da177e4SLinus Torvalds 	u32 index;
4471da177e4SLinus Torvalds 	int status = 0;
4481da177e4SLinus Torvalds 	struct fib * fibptr;
4491da177e4SLinus Torvalds 	struct aac_get_container_count *dinfo;
4501da177e4SLinus Torvalds 	struct aac_get_container_count_resp *dresp;
4511da177e4SLinus Torvalds 	int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
4521da177e4SLinus Torvalds 
453bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
4541da177e4SLinus Torvalds 		return -ENOMEM;
4551da177e4SLinus Torvalds 
456bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
4571da177e4SLinus Torvalds 	dinfo = (struct aac_get_container_count *) fib_data(fibptr);
4581da177e4SLinus Torvalds 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
4591da177e4SLinus Torvalds 	dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
4601da177e4SLinus Torvalds 
461bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
4621da177e4SLinus Torvalds 		    fibptr,
4631da177e4SLinus Torvalds 		    sizeof (struct aac_get_container_count),
4641da177e4SLinus Torvalds 		    FsaNormal,
4651da177e4SLinus Torvalds 		    1, 1,
4661da177e4SLinus Torvalds 		    NULL, NULL);
4671da177e4SLinus Torvalds 	if (status >= 0) {
4681da177e4SLinus Torvalds 		dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
4691da177e4SLinus Torvalds 		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
470a7129a54SMahesh Rajashekhara 		if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
471a7129a54SMahesh Rajashekhara 		    AAC_OPTION_SUPPORTED_240_VOLUMES) {
472a7129a54SMahesh Rajashekhara 			maximum_num_containers =
473a7129a54SMahesh Rajashekhara 				le32_to_cpu(dresp->MaxSimpleVolumes);
474a7129a54SMahesh Rajashekhara 		}
475bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
4761da177e4SLinus Torvalds 	}
477cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
478cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status != -ERESTARTSYS)
479fe76df42SMark Haverkamp 		aac_fib_free(fibptr);
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
4821da177e4SLinus Torvalds 		maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
4833ffd6c5aSRaghava Aditya Renukunta 	if (dev->fsa_dev == NULL ||
4843ffd6c5aSRaghava Aditya Renukunta 		dev->maximum_num_containers != maximum_num_containers) {
4853ffd6c5aSRaghava Aditya Renukunta 
4863ffd6c5aSRaghava Aditya Renukunta 		fsa_dev_ptr = dev->fsa_dev;
4873ffd6c5aSRaghava Aditya Renukunta 
4883ffd6c5aSRaghava Aditya Renukunta 		dev->fsa_dev = kcalloc(maximum_num_containers,
4893ffd6c5aSRaghava Aditya Renukunta 					sizeof(*fsa_dev_ptr), GFP_KERNEL);
4903ffd6c5aSRaghava Aditya Renukunta 
4913ffd6c5aSRaghava Aditya Renukunta 		kfree(fsa_dev_ptr);
4923ffd6c5aSRaghava Aditya Renukunta 		fsa_dev_ptr = NULL;
4933ffd6c5aSRaghava Aditya Renukunta 
4943ffd6c5aSRaghava Aditya Renukunta 
4953ffd6c5aSRaghava Aditya Renukunta 		if (!dev->fsa_dev)
4961da177e4SLinus Torvalds 			return -ENOMEM;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 		dev->maximum_num_containers = maximum_num_containers;
4993ffd6c5aSRaghava Aditya Renukunta 	}
5003ffd6c5aSRaghava Aditya Renukunta 	for (index = 0; index < dev->maximum_num_containers; index++) {
5013ffd6c5aSRaghava Aditya Renukunta 		dev->fsa_dev[index].devname[0] = '\0';
5023ffd6c5aSRaghava Aditya Renukunta 		dev->fsa_dev[index].valid = 0;
5031da177e4SLinus Torvalds 
504fe76df42SMark Haverkamp 		status = aac_probe_container(dev, index);
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 		if (status < 0) {
5071da177e4SLinus Torvalds 			printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
5081da177e4SLinus Torvalds 			break;
5091da177e4SLinus Torvalds 		}
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 	return status;
5121da177e4SLinus Torvalds }
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds static void get_container_name_callback(void *context, struct fib * fibptr)
5151da177e4SLinus Torvalds {
5161da177e4SLinus Torvalds 	struct aac_get_name_resp * get_name_reply;
5171da177e4SLinus Torvalds 	struct scsi_cmnd * scsicmd;
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
5201da177e4SLinus Torvalds 
52103d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
52203d44337SMark Haverkamp 		return;
52303d44337SMark Haverkamp 
5241da177e4SLinus Torvalds 	dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
525125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds 	get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
5281da177e4SLinus Torvalds 	/* Failure is irrelevant, using default value instead */
5291da177e4SLinus Torvalds 	if ((le32_to_cpu(get_name_reply->status) == CT_OK)
5301da177e4SLinus Torvalds 	 && (get_name_reply->data[0] != '\0')) {
5311da177e4SLinus Torvalds 		char *sp = get_name_reply->data;
532b836439fSMahesh Rajashekhara 		sp[sizeof(((struct aac_get_name_resp *)NULL)->data)] = '\0';
5331da177e4SLinus Torvalds 		while (*sp == ' ')
5341da177e4SLinus Torvalds 			++sp;
5353b2946ccSMark Haverkamp 		if (*sp) {
536d4345028SFUJITA Tomonori 			struct inquiry_data inq;
5373b2946ccSMark Haverkamp 			char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
5383b2946ccSMark Haverkamp 			int count = sizeof(d);
5393b2946ccSMark Haverkamp 			char *dp = d;
5403b2946ccSMark Haverkamp 			do {
5411da177e4SLinus Torvalds 				*dp++ = (*sp) ? *sp++ : ' ';
5421da177e4SLinus Torvalds 			} while (--count > 0);
543d4345028SFUJITA Tomonori 
544d4345028SFUJITA Tomonori 			scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq));
545d4345028SFUJITA Tomonori 			memcpy(inq.inqd_pid, d, sizeof(d));
546d4345028SFUJITA Tomonori 			scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq));
5471da177e4SLinus Torvalds 		}
5483b2946ccSMark Haverkamp 	}
5493b2946ccSMark Haverkamp 
5501da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
5511da177e4SLinus Torvalds 
552bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
5538e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
5541da177e4SLinus Torvalds }
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds /**
5571da177e4SLinus Torvalds  *	aac_get_container_name	-	get container name, none blocking.
5581da177e4SLinus Torvalds  */
5599e7c349cSMark Haverkamp static int aac_get_container_name(struct scsi_cmnd * scsicmd)
5601da177e4SLinus Torvalds {
5611da177e4SLinus Torvalds 	int status;
5621da177e4SLinus Torvalds 	struct aac_get_name *dinfo;
5631da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
5641da177e4SLinus Torvalds 	struct aac_dev * dev;
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
5671da177e4SLinus Torvalds 
5686bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
5691da177e4SLinus Torvalds 
570bfb35aa8SMark Haverkamp 	aac_fib_init(cmd_fibcontext);
5711da177e4SLinus Torvalds 	dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
5741da177e4SLinus Torvalds 	dinfo->type = cpu_to_le32(CT_READ_NAME);
5759e7c349cSMark Haverkamp 	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
5761da177e4SLinus Torvalds 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
5771da177e4SLinus Torvalds 
578bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
5791da177e4SLinus Torvalds 		  cmd_fibcontext,
580fb5d40d4SMahesh Rajashekhara 		  sizeof(struct aac_get_name_resp),
5811da177e4SLinus Torvalds 		  FsaNormal,
5821da177e4SLinus Torvalds 		  0, 1,
5831da177e4SLinus Torvalds 		  (fib_callback)get_container_name_callback,
5841da177e4SLinus Torvalds 		  (void *) scsicmd);
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 	/*
5871da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
5881da177e4SLinus Torvalds 	 */
58977d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
59077d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
5911da177e4SLinus Torvalds 		return 0;
59277d644d4SMark Haverkamp 	}
5931da177e4SLinus Torvalds 
594bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
595bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
5961da177e4SLinus Torvalds 	return -1;
5971da177e4SLinus Torvalds }
5981da177e4SLinus Torvalds 
599fe76df42SMark Haverkamp static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
600fe76df42SMark Haverkamp {
601fe76df42SMark Haverkamp 	struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
602fe76df42SMark Haverkamp 
6031a655040SSalyzyn, Mark 	if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))
604fe76df42SMark Haverkamp 		return aac_scsi_cmd(scsicmd);
605fe76df42SMark Haverkamp 
606fe76df42SMark Haverkamp 	scsicmd->result = DID_NO_CONNECT << 16;
607fe76df42SMark Haverkamp 	scsicmd->scsi_done(scsicmd);
608fe76df42SMark Haverkamp 	return 0;
609fe76df42SMark Haverkamp }
610fe76df42SMark Haverkamp 
6111a655040SSalyzyn, Mark static void _aac_probe_container2(void * context, struct fib * fibptr)
612fe76df42SMark Haverkamp {
61303d44337SMark Haverkamp 	struct fsa_dev_info *fsa_dev_ptr;
614fe76df42SMark Haverkamp 	int (*callback)(struct scsi_cmnd *);
61503d44337SMark Haverkamp 	struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
61603d44337SMark Haverkamp 
61703d44337SMark Haverkamp 
6181a655040SSalyzyn, Mark 	if (!aac_valid_context(scsicmd, fibptr))
6191a655040SSalyzyn, Mark 		return;
620fe76df42SMark Haverkamp 
621fe76df42SMark Haverkamp 	scsicmd->SCp.Status = 0;
6221a655040SSalyzyn, Mark 	fsa_dev_ptr = fibptr->dev->fsa_dev;
623fe76df42SMark Haverkamp 	if (fsa_dev_ptr) {
624fe76df42SMark Haverkamp 		struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
625fe76df42SMark Haverkamp 		fsa_dev_ptr += scmd_id(scsicmd);
626fe76df42SMark Haverkamp 
627fe76df42SMark Haverkamp 		if ((le32_to_cpu(dresp->status) == ST_OK) &&
628fe76df42SMark Haverkamp 		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
629fe76df42SMark Haverkamp 		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
630b836439fSMahesh Rajashekhara 			if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 &
631b836439fSMahesh Rajashekhara 			    AAC_OPTION_VARIABLE_BLOCK_SIZE)) {
632b836439fSMahesh Rajashekhara 				dresp->mnt[0].fileinfo.bdevinfo.block_size = 0x200;
633b836439fSMahesh Rajashekhara 				fsa_dev_ptr->block_size = 0x200;
634b836439fSMahesh Rajashekhara 			} else {
635b836439fSMahesh Rajashekhara 				fsa_dev_ptr->block_size =
636b836439fSMahesh Rajashekhara 					le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size);
637b836439fSMahesh Rajashekhara 			}
638fe76df42SMark Haverkamp 			fsa_dev_ptr->valid = 1;
639655d722cSMark Salyzyn 			/* sense_key holds the current state of the spin-up */
640655d722cSMark Salyzyn 			if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
641655d722cSMark Salyzyn 				fsa_dev_ptr->sense_data.sense_key = NOT_READY;
642655d722cSMark Salyzyn 			else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
643655d722cSMark Salyzyn 				fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
644fe76df42SMark Haverkamp 			fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
645fe76df42SMark Haverkamp 			fsa_dev_ptr->size
646fe76df42SMark Haverkamp 			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
647fe76df42SMark Haverkamp 			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
648fe76df42SMark Haverkamp 			fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
649fe76df42SMark Haverkamp 		}
650fe76df42SMark Haverkamp 		if ((fsa_dev_ptr->valid & 1) == 0)
651fe76df42SMark Haverkamp 			fsa_dev_ptr->valid = 0;
652fe76df42SMark Haverkamp 		scsicmd->SCp.Status = le32_to_cpu(dresp->count);
653fe76df42SMark Haverkamp 	}
654fe76df42SMark Haverkamp 	aac_fib_complete(fibptr);
655fe76df42SMark Haverkamp 	aac_fib_free(fibptr);
656fe76df42SMark Haverkamp 	callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
657fe76df42SMark Haverkamp 	scsicmd->SCp.ptr = NULL;
6581a655040SSalyzyn, Mark 	(*callback)(scsicmd);
6591a655040SSalyzyn, Mark 	return;
660fe76df42SMark Haverkamp }
661fe76df42SMark Haverkamp 
6621a655040SSalyzyn, Mark static void _aac_probe_container1(void * context, struct fib * fibptr)
663fe76df42SMark Haverkamp {
664fe76df42SMark Haverkamp 	struct scsi_cmnd * scsicmd;
665fe76df42SMark Haverkamp 	struct aac_mount * dresp;
666fe76df42SMark Haverkamp 	struct aac_query_mount *dinfo;
667fe76df42SMark Haverkamp 	int status;
668fe76df42SMark Haverkamp 
669fe76df42SMark Haverkamp 	dresp = (struct aac_mount *) fib_data(fibptr);
670b836439fSMahesh Rajashekhara 	if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 &
671b836439fSMahesh Rajashekhara 	    AAC_OPTION_VARIABLE_BLOCK_SIZE))
672fe76df42SMark Haverkamp 		dresp->mnt[0].capacityhigh = 0;
673fe76df42SMark Haverkamp 	if ((le32_to_cpu(dresp->status) != ST_OK) ||
6741a655040SSalyzyn, Mark 	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
6751a655040SSalyzyn, Mark 		_aac_probe_container2(context, fibptr);
6761a655040SSalyzyn, Mark 		return;
6771a655040SSalyzyn, Mark 	}
678fe76df42SMark Haverkamp 	scsicmd = (struct scsi_cmnd *) context;
679fe76df42SMark Haverkamp 
68003d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
6811a655040SSalyzyn, Mark 		return;
68203d44337SMark Haverkamp 
683fe76df42SMark Haverkamp 	aac_fib_init(fibptr);
684fe76df42SMark Haverkamp 
685fe76df42SMark Haverkamp 	dinfo = (struct aac_query_mount *)fib_data(fibptr);
686fe76df42SMark Haverkamp 
687b836439fSMahesh Rajashekhara 	if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
688b836439fSMahesh Rajashekhara 	    AAC_OPTION_VARIABLE_BLOCK_SIZE)
689b836439fSMahesh Rajashekhara 		dinfo->command = cpu_to_le32(VM_NameServeAllBlk);
690b836439fSMahesh Rajashekhara 	else
691fe76df42SMark Haverkamp 		dinfo->command = cpu_to_le32(VM_NameServe64);
692b836439fSMahesh Rajashekhara 
693fe76df42SMark Haverkamp 	dinfo->count = cpu_to_le32(scmd_id(scsicmd));
694fe76df42SMark Haverkamp 	dinfo->type = cpu_to_le32(FT_FILESYS);
695fe76df42SMark Haverkamp 
696fe76df42SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
697fe76df42SMark Haverkamp 			  fibptr,
698fe76df42SMark Haverkamp 			  sizeof(struct aac_query_mount),
699fe76df42SMark Haverkamp 			  FsaNormal,
700fe76df42SMark Haverkamp 			  0, 1,
7011a655040SSalyzyn, Mark 			  _aac_probe_container2,
702fe76df42SMark Haverkamp 			  (void *) scsicmd);
703fe76df42SMark Haverkamp 	/*
704fe76df42SMark Haverkamp 	 *	Check that the command queued to the controller
705fe76df42SMark Haverkamp 	 */
7061a655040SSalyzyn, Mark 	if (status == -EINPROGRESS)
707fe76df42SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
7081a655040SSalyzyn, Mark 	else if (status < 0) {
709fe76df42SMark Haverkamp 		/* Inherit results from VM_NameServe, if any */
710fe76df42SMark Haverkamp 		dresp->status = cpu_to_le32(ST_OK);
7111a655040SSalyzyn, Mark 		_aac_probe_container2(context, fibptr);
712fe76df42SMark Haverkamp 	}
713fe76df42SMark Haverkamp }
714fe76df42SMark Haverkamp 
715fe76df42SMark Haverkamp static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
716fe76df42SMark Haverkamp {
717fe76df42SMark Haverkamp 	struct fib * fibptr;
718fe76df42SMark Haverkamp 	int status = -ENOMEM;
719fe76df42SMark Haverkamp 
720fe76df42SMark Haverkamp 	if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
721fe76df42SMark Haverkamp 		struct aac_query_mount *dinfo;
722fe76df42SMark Haverkamp 
723fe76df42SMark Haverkamp 		aac_fib_init(fibptr);
724fe76df42SMark Haverkamp 
725fe76df42SMark Haverkamp 		dinfo = (struct aac_query_mount *)fib_data(fibptr);
726fe76df42SMark Haverkamp 
727b836439fSMahesh Rajashekhara 		if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
728b836439fSMahesh Rajashekhara 		    AAC_OPTION_VARIABLE_BLOCK_SIZE)
729b836439fSMahesh Rajashekhara 			dinfo->command = cpu_to_le32(VM_NameServeAllBlk);
730b836439fSMahesh Rajashekhara 		else
731fe76df42SMark Haverkamp 			dinfo->command = cpu_to_le32(VM_NameServe);
732b836439fSMahesh Rajashekhara 
733fe76df42SMark Haverkamp 		dinfo->count = cpu_to_le32(scmd_id(scsicmd));
734fe76df42SMark Haverkamp 		dinfo->type = cpu_to_le32(FT_FILESYS);
735fe76df42SMark Haverkamp 		scsicmd->SCp.ptr = (char *)callback;
736fe76df42SMark Haverkamp 
737fe76df42SMark Haverkamp 		status = aac_fib_send(ContainerCommand,
738fe76df42SMark Haverkamp 			  fibptr,
739fe76df42SMark Haverkamp 			  sizeof(struct aac_query_mount),
740fe76df42SMark Haverkamp 			  FsaNormal,
741fe76df42SMark Haverkamp 			  0, 1,
7421a655040SSalyzyn, Mark 			  _aac_probe_container1,
743fe76df42SMark Haverkamp 			  (void *) scsicmd);
744fe76df42SMark Haverkamp 		/*
745fe76df42SMark Haverkamp 		 *	Check that the command queued to the controller
746fe76df42SMark Haverkamp 		 */
747fe76df42SMark Haverkamp 		if (status == -EINPROGRESS) {
748fe76df42SMark Haverkamp 			scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
749fe76df42SMark Haverkamp 			return 0;
750fe76df42SMark Haverkamp 		}
751fe76df42SMark Haverkamp 		if (status < 0) {
752fe76df42SMark Haverkamp 			scsicmd->SCp.ptr = NULL;
753fe76df42SMark Haverkamp 			aac_fib_complete(fibptr);
754fe76df42SMark Haverkamp 			aac_fib_free(fibptr);
755fe76df42SMark Haverkamp 		}
756fe76df42SMark Haverkamp 	}
757fe76df42SMark Haverkamp 	if (status < 0) {
758fe76df42SMark Haverkamp 		struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
759fe76df42SMark Haverkamp 		if (fsa_dev_ptr) {
760fe76df42SMark Haverkamp 			fsa_dev_ptr += scmd_id(scsicmd);
761fe76df42SMark Haverkamp 			if ((fsa_dev_ptr->valid & 1) == 0) {
762fe76df42SMark Haverkamp 				fsa_dev_ptr->valid = 0;
763fe76df42SMark Haverkamp 				return (*callback)(scsicmd);
764fe76df42SMark Haverkamp 			}
765fe76df42SMark Haverkamp 		}
766fe76df42SMark Haverkamp 	}
767fe76df42SMark Haverkamp 	return status;
768fe76df42SMark Haverkamp }
769fe76df42SMark Haverkamp 
7701da177e4SLinus Torvalds /**
771bfb35aa8SMark Haverkamp  *	aac_probe_container		-	query a logical volume
7721da177e4SLinus Torvalds  *	@dev: device to query
7731da177e4SLinus Torvalds  *	@cid: container identifier
7741da177e4SLinus Torvalds  *
7751da177e4SLinus Torvalds  *	Queries the controller about the given volume. The volume information
7761da177e4SLinus Torvalds  *	is updated in the struct fsa_dev_info structure rather than returned.
7771da177e4SLinus Torvalds  */
778fe76df42SMark Haverkamp static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
779fe76df42SMark Haverkamp {
780fe76df42SMark Haverkamp 	scsicmd->device = NULL;
781fe76df42SMark Haverkamp 	return 0;
782fe76df42SMark Haverkamp }
7831da177e4SLinus Torvalds 
784bfb35aa8SMark Haverkamp int aac_probe_container(struct aac_dev *dev, int cid)
7851da177e4SLinus Torvalds {
786fe76df42SMark Haverkamp 	struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
787fe76df42SMark Haverkamp 	struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
7881da177e4SLinus Torvalds 	int status;
7891da177e4SLinus Torvalds 
790fe76df42SMark Haverkamp 	if (!scsicmd || !scsidev) {
791fe76df42SMark Haverkamp 		kfree(scsicmd);
792fe76df42SMark Haverkamp 		kfree(scsidev);
79390ee3466SMark Haverkamp 		return -ENOMEM;
7941da177e4SLinus Torvalds 	}
795fe76df42SMark Haverkamp 	scsicmd->list.next = NULL;
7961a655040SSalyzyn, Mark 	scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;
7971da177e4SLinus Torvalds 
798fe76df42SMark Haverkamp 	scsicmd->device = scsidev;
799fe76df42SMark Haverkamp 	scsidev->sdev_state = 0;
800fe76df42SMark Haverkamp 	scsidev->id = cid;
801fe76df42SMark Haverkamp 	scsidev->host = dev->scsi_host_ptr;
8021da177e4SLinus Torvalds 
803fe76df42SMark Haverkamp 	if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
804fe76df42SMark Haverkamp 		while (scsicmd->device == scsidev)
805fe76df42SMark Haverkamp 			schedule();
806802ae2f0SSalyzyn, Mark 	kfree(scsidev);
807fe76df42SMark Haverkamp 	status = scsicmd->SCp.Status;
808fe76df42SMark Haverkamp 	kfree(scsicmd);
8091da177e4SLinus Torvalds 	return status;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds /* Local Structure to set SCSI inquiry data strings */
8131da177e4SLinus Torvalds struct scsi_inq {
8141da177e4SLinus Torvalds 	char vid[8];         /* Vendor ID */
8151da177e4SLinus Torvalds 	char pid[16];        /* Product ID */
8161da177e4SLinus Torvalds 	char prl[4];         /* Product Revision Level */
8171da177e4SLinus Torvalds };
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds /**
8201da177e4SLinus Torvalds  *	InqStrCopy	-	string merge
8211da177e4SLinus Torvalds  *	@a:	string to copy from
8221da177e4SLinus Torvalds  *	@b:	string to copy to
8231da177e4SLinus Torvalds  *
8241da177e4SLinus Torvalds  *	Copy a String from one location to another
8251da177e4SLinus Torvalds  *	without copying \0
8261da177e4SLinus Torvalds  */
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds static void inqstrcpy(char *a, char *b)
8291da177e4SLinus Torvalds {
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds 	while (*a != (char)0)
8321da177e4SLinus Torvalds 		*b++ = *a++;
8331da177e4SLinus Torvalds }
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds static char *container_types[] = {
8361da177e4SLinus Torvalds 	"None",
8371da177e4SLinus Torvalds 	"Volume",
8381da177e4SLinus Torvalds 	"Mirror",
8391da177e4SLinus Torvalds 	"Stripe",
8401da177e4SLinus Torvalds 	"RAID5",
8411da177e4SLinus Torvalds 	"SSRW",
8421da177e4SLinus Torvalds 	"SSRO",
8431da177e4SLinus Torvalds 	"Morph",
8441da177e4SLinus Torvalds 	"Legacy",
8451da177e4SLinus Torvalds 	"RAID4",
8461da177e4SLinus Torvalds 	"RAID10",
8471da177e4SLinus Torvalds 	"RAID00",
8481da177e4SLinus Torvalds 	"V-MIRRORS",
8491da177e4SLinus Torvalds 	"PSEUDO R4",
8501da177e4SLinus Torvalds 	"RAID50",
85184971738SMark Haverkamp 	"RAID5D",
85284971738SMark Haverkamp 	"RAID5D0",
85384971738SMark Haverkamp 	"RAID1E",
85484971738SMark Haverkamp 	"RAID6",
85584971738SMark Haverkamp 	"RAID60",
8561da177e4SLinus Torvalds 	"Unknown"
8571da177e4SLinus Torvalds };
8581da177e4SLinus Torvalds 
85917eaaceeSSalyzyn, Mark char * get_container_type(unsigned tindex)
86017eaaceeSSalyzyn, Mark {
86117eaaceeSSalyzyn, Mark 	if (tindex >= ARRAY_SIZE(container_types))
86217eaaceeSSalyzyn, Mark 		tindex = ARRAY_SIZE(container_types) - 1;
86317eaaceeSSalyzyn, Mark 	return container_types[tindex];
86417eaaceeSSalyzyn, Mark }
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds /* Function: setinqstr
8671da177e4SLinus Torvalds  *
8681da177e4SLinus Torvalds  * Arguments: [1] pointer to void [1] int
8691da177e4SLinus Torvalds  *
8701da177e4SLinus Torvalds  * Purpose: Sets SCSI inquiry data strings for vendor, product
87125985edcSLucas De Marchi  * and revision level. Allows strings to be set in platform dependent
87225985edcSLucas De Marchi  * files instead of in OS dependent driver source.
8731da177e4SLinus Torvalds  */
8741da177e4SLinus Torvalds 
875794d0601SMark Haverkamp static void setinqstr(struct aac_dev *dev, void *data, int tindex)
8761da177e4SLinus Torvalds {
8771da177e4SLinus Torvalds 	struct scsi_inq *str;
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds 	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
880794d0601SMark Haverkamp 	memset(str, ' ', sizeof(*str));
881794d0601SMark Haverkamp 
882794d0601SMark Haverkamp 	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
883794d0601SMark Haverkamp 		char * cp = dev->supplement_adapter_info.AdapterTypeText;
8843bc8070fSSalyzyn, Mark 		int c;
8853bc8070fSSalyzyn, Mark 		if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
8863bc8070fSSalyzyn, Mark 			inqstrcpy("SMC", str->vid);
8873bc8070fSSalyzyn, Mark 		else {
8883bc8070fSSalyzyn, Mark 			c = sizeof(str->vid);
889794d0601SMark Haverkamp 			while (*cp && *cp != ' ' && --c)
890794d0601SMark Haverkamp 				++cp;
891794d0601SMark Haverkamp 			c = *cp;
892794d0601SMark Haverkamp 			*cp = '\0';
893794d0601SMark Haverkamp 			inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
894794d0601SMark Haverkamp 				   str->vid);
895794d0601SMark Haverkamp 			*cp = c;
896794d0601SMark Haverkamp 			while (*cp && *cp != ' ')
897794d0601SMark Haverkamp 				++cp;
8983bc8070fSSalyzyn, Mark 		}
899794d0601SMark Haverkamp 		while (*cp == ' ')
900794d0601SMark Haverkamp 			++cp;
901794d0601SMark Haverkamp 		/* last six chars reserved for vol type */
902794d0601SMark Haverkamp 		c = 0;
903794d0601SMark Haverkamp 		if (strlen(cp) > sizeof(str->pid)) {
904794d0601SMark Haverkamp 			c = cp[sizeof(str->pid)];
905794d0601SMark Haverkamp 			cp[sizeof(str->pid)] = '\0';
906794d0601SMark Haverkamp 		}
907794d0601SMark Haverkamp 		inqstrcpy (cp, str->pid);
908794d0601SMark Haverkamp 		if (c)
909794d0601SMark Haverkamp 			cp[sizeof(str->pid)] = c;
910794d0601SMark Haverkamp 	} else {
911794d0601SMark Haverkamp 		struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 		inqstrcpy (mp->vname, str->vid);
914794d0601SMark Haverkamp 		/* last six chars reserved for vol type */
915794d0601SMark Haverkamp 		inqstrcpy (mp->model, str->pid);
916794d0601SMark Haverkamp 	}
9171da177e4SLinus Torvalds 
9186391a113STobias Klauser 	if (tindex < ARRAY_SIZE(container_types)){
9191da177e4SLinus Torvalds 		char *findit = str->pid;
9201da177e4SLinus Torvalds 
9211da177e4SLinus Torvalds 		for ( ; *findit != ' '; findit++); /* walk till we find a space */
9221da177e4SLinus Torvalds 		/* RAID is superfluous in the context of a RAID device */
9231da177e4SLinus Torvalds 		if (memcmp(findit-4, "RAID", 4) == 0)
9241da177e4SLinus Torvalds 			*(findit -= 4) = ' ';
925794d0601SMark Haverkamp 		if (((findit - str->pid) + strlen(container_types[tindex]))
926794d0601SMark Haverkamp 		 < (sizeof(str->pid) + sizeof(str->prl)))
9271da177e4SLinus Torvalds 			inqstrcpy (container_types[tindex], findit + 1);
9281da177e4SLinus Torvalds 	}
9291da177e4SLinus Torvalds 	inqstrcpy ("V1.0", str->prl);
9301da177e4SLinus Torvalds }
9311da177e4SLinus Torvalds 
93288e2f98eSSalyzyn, Mark static void get_container_serial_callback(void *context, struct fib * fibptr)
93388e2f98eSSalyzyn, Mark {
93488e2f98eSSalyzyn, Mark 	struct aac_get_serial_resp * get_serial_reply;
93588e2f98eSSalyzyn, Mark 	struct scsi_cmnd * scsicmd;
93688e2f98eSSalyzyn, Mark 
93788e2f98eSSalyzyn, Mark 	BUG_ON(fibptr == NULL);
93888e2f98eSSalyzyn, Mark 
93988e2f98eSSalyzyn, Mark 	scsicmd = (struct scsi_cmnd *) context;
94088e2f98eSSalyzyn, Mark 	if (!aac_valid_context(scsicmd, fibptr))
94188e2f98eSSalyzyn, Mark 		return;
94288e2f98eSSalyzyn, Mark 
94388e2f98eSSalyzyn, Mark 	get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
94488e2f98eSSalyzyn, Mark 	/* Failure is irrelevant, using default value instead */
94588e2f98eSSalyzyn, Mark 	if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
9465d910649SMahesh Rajashekhara 		/*Check to see if it's for VPD 0x83 or 0x80 */
9475d910649SMahesh Rajashekhara 		if (scsicmd->cmnd[2] == 0x83) {
9485d910649SMahesh Rajashekhara 			/* vpd page 0x83 - Device Identification Page */
9495d910649SMahesh Rajashekhara 			int i;
9505d910649SMahesh Rajashekhara 			TVPD_Page83 VPDPage83Data;
9515d910649SMahesh Rajashekhara 
9525d910649SMahesh Rajashekhara 			memset(((u8 *)&VPDPage83Data), 0,
9535d910649SMahesh Rajashekhara 			       sizeof(VPDPage83Data));
9545d910649SMahesh Rajashekhara 
9555d910649SMahesh Rajashekhara 			/* DIRECT_ACCESS_DEVIC */
9565d910649SMahesh Rajashekhara 			VPDPage83Data.DeviceType = 0;
9575d910649SMahesh Rajashekhara 			/* DEVICE_CONNECTED */
9585d910649SMahesh Rajashekhara 			VPDPage83Data.DeviceTypeQualifier = 0;
9595d910649SMahesh Rajashekhara 			/* VPD_DEVICE_IDENTIFIERS */
9605d910649SMahesh Rajashekhara 			VPDPage83Data.PageCode = 0x83;
9615d910649SMahesh Rajashekhara 			VPDPage83Data.Reserved = 0;
9625d910649SMahesh Rajashekhara 			VPDPage83Data.PageLength =
9635d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType1) +
9645d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType2);
9655d910649SMahesh Rajashekhara 
9665d910649SMahesh Rajashekhara 			/* T10 Vendor Identifier Field Format */
9675d910649SMahesh Rajashekhara 			/* VpdCodeSetAscii */
9685d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType1.CodeSet = 2;
9695d910649SMahesh Rajashekhara 			/* VpdIdentifierTypeVendorId */
9705d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType1.IdentifierType = 1;
9715d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType1.IdentifierLength =
9725d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType1) - 4;
9735d910649SMahesh Rajashekhara 
9745d910649SMahesh Rajashekhara 			/* "ADAPTEC " for adaptec */
9755d910649SMahesh Rajashekhara 			memcpy(VPDPage83Data.IdDescriptorType1.VendId,
9765d910649SMahesh Rajashekhara 				"ADAPTEC ",
9775d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType1.VendId));
9785d910649SMahesh Rajashekhara 			memcpy(VPDPage83Data.IdDescriptorType1.ProductId,
9795d910649SMahesh Rajashekhara 				"ARRAY           ",
9805d910649SMahesh Rajashekhara 				sizeof(
9815d910649SMahesh Rajashekhara 				VPDPage83Data.IdDescriptorType1.ProductId));
9825d910649SMahesh Rajashekhara 
9835d910649SMahesh Rajashekhara 			/* Convert to ascii based serial number.
9845d910649SMahesh Rajashekhara 			 * The LSB is the the end.
9855d910649SMahesh Rajashekhara 			 */
9865d910649SMahesh Rajashekhara 			for (i = 0; i < 8; i++) {
9875d910649SMahesh Rajashekhara 				u8 temp =
9885d910649SMahesh Rajashekhara 					(u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF);
9895d910649SMahesh Rajashekhara 				if (temp  > 0x9) {
9905d910649SMahesh Rajashekhara 					VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
9915d910649SMahesh Rajashekhara 							'A' + (temp - 0xA);
9925d910649SMahesh Rajashekhara 				} else {
9935d910649SMahesh Rajashekhara 					VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
9945d910649SMahesh Rajashekhara 							'0' + temp;
9955d910649SMahesh Rajashekhara 				}
9965d910649SMahesh Rajashekhara 			}
9975d910649SMahesh Rajashekhara 
9985d910649SMahesh Rajashekhara 			/* VpdCodeSetBinary */
9995d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.CodeSet = 1;
10005d910649SMahesh Rajashekhara 			/* VpdIdentifierTypeEUI64 */
10015d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.IdentifierType = 2;
10025d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.IdentifierLength =
10035d910649SMahesh Rajashekhara 				sizeof(VPDPage83Data.IdDescriptorType2) - 4;
10045d910649SMahesh Rajashekhara 
10055d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0;
10065d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0;
10075d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0;
10085d910649SMahesh Rajashekhara 
10095d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.Serial =
10105d910649SMahesh Rajashekhara 							get_serial_reply->uid;
10115d910649SMahesh Rajashekhara 			VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0;
10125d910649SMahesh Rajashekhara 
10135d910649SMahesh Rajashekhara 			/* Move the inquiry data to the response buffer. */
10145d910649SMahesh Rajashekhara 			scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data,
10155d910649SMahesh Rajashekhara 						 sizeof(VPDPage83Data));
10165d910649SMahesh Rajashekhara 		} else {
10175d910649SMahesh Rajashekhara 			/* It must be for VPD 0x80 */
101888e2f98eSSalyzyn, Mark 			char sp[13];
101988e2f98eSSalyzyn, Mark 			/* EVPD bit set */
102088e2f98eSSalyzyn, Mark 			sp[0] = INQD_PDT_DA;
102188e2f98eSSalyzyn, Mark 			sp[1] = scsicmd->cmnd[2];
102288e2f98eSSalyzyn, Mark 			sp[2] = 0;
102388e2f98eSSalyzyn, Mark 			sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
102488e2f98eSSalyzyn, Mark 				le32_to_cpu(get_serial_reply->uid));
10255d910649SMahesh Rajashekhara 			scsi_sg_copy_from_buffer(scsicmd, sp,
10265d910649SMahesh Rajashekhara 						 sizeof(sp));
10275d910649SMahesh Rajashekhara 		}
102888e2f98eSSalyzyn, Mark 	}
102988e2f98eSSalyzyn, Mark 
103088e2f98eSSalyzyn, Mark 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
103188e2f98eSSalyzyn, Mark 
103288e2f98eSSalyzyn, Mark 	aac_fib_complete(fibptr);
103388e2f98eSSalyzyn, Mark 	scsicmd->scsi_done(scsicmd);
103488e2f98eSSalyzyn, Mark }
103588e2f98eSSalyzyn, Mark 
103688e2f98eSSalyzyn, Mark /**
103788e2f98eSSalyzyn, Mark  *	aac_get_container_serial - get container serial, none blocking.
103888e2f98eSSalyzyn, Mark  */
103988e2f98eSSalyzyn, Mark static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
104088e2f98eSSalyzyn, Mark {
104188e2f98eSSalyzyn, Mark 	int status;
104288e2f98eSSalyzyn, Mark 	struct aac_get_serial *dinfo;
104388e2f98eSSalyzyn, Mark 	struct fib * cmd_fibcontext;
104488e2f98eSSalyzyn, Mark 	struct aac_dev * dev;
104588e2f98eSSalyzyn, Mark 
104688e2f98eSSalyzyn, Mark 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
104788e2f98eSSalyzyn, Mark 
10486bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
104988e2f98eSSalyzyn, Mark 
105088e2f98eSSalyzyn, Mark 	aac_fib_init(cmd_fibcontext);
105188e2f98eSSalyzyn, Mark 	dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
105288e2f98eSSalyzyn, Mark 
105388e2f98eSSalyzyn, Mark 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
105488e2f98eSSalyzyn, Mark 	dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
105588e2f98eSSalyzyn, Mark 	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
105688e2f98eSSalyzyn, Mark 
105788e2f98eSSalyzyn, Mark 	status = aac_fib_send(ContainerCommand,
105888e2f98eSSalyzyn, Mark 		  cmd_fibcontext,
1059fb5d40d4SMahesh Rajashekhara 		  sizeof(struct aac_get_serial_resp),
106088e2f98eSSalyzyn, Mark 		  FsaNormal,
106188e2f98eSSalyzyn, Mark 		  0, 1,
106288e2f98eSSalyzyn, Mark 		  (fib_callback) get_container_serial_callback,
106388e2f98eSSalyzyn, Mark 		  (void *) scsicmd);
106488e2f98eSSalyzyn, Mark 
106588e2f98eSSalyzyn, Mark 	/*
106688e2f98eSSalyzyn, Mark 	 *	Check that the command queued to the controller
106788e2f98eSSalyzyn, Mark 	 */
106888e2f98eSSalyzyn, Mark 	if (status == -EINPROGRESS) {
106988e2f98eSSalyzyn, Mark 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
107088e2f98eSSalyzyn, Mark 		return 0;
107188e2f98eSSalyzyn, Mark 	}
107288e2f98eSSalyzyn, Mark 
107388e2f98eSSalyzyn, Mark 	printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
107488e2f98eSSalyzyn, Mark 	aac_fib_complete(cmd_fibcontext);
107588e2f98eSSalyzyn, Mark 	return -1;
107688e2f98eSSalyzyn, Mark }
107788e2f98eSSalyzyn, Mark 
107888e2f98eSSalyzyn, Mark /* Function: setinqserial
107988e2f98eSSalyzyn, Mark  *
108088e2f98eSSalyzyn, Mark  * Arguments: [1] pointer to void [1] int
108188e2f98eSSalyzyn, Mark  *
108288e2f98eSSalyzyn, Mark  * Purpose: Sets SCSI Unit Serial number.
108388e2f98eSSalyzyn, Mark  *          This is a fake. We should read a proper
108488e2f98eSSalyzyn, Mark  *          serial number from the container. <SuSE>But
108588e2f98eSSalyzyn, Mark  *          without docs it's quite hard to do it :-)
108688e2f98eSSalyzyn, Mark  *          So this will have to do in the meantime.</SuSE>
108788e2f98eSSalyzyn, Mark  */
108888e2f98eSSalyzyn, Mark 
108988e2f98eSSalyzyn, Mark static int setinqserial(struct aac_dev *dev, void *data, int cid)
109088e2f98eSSalyzyn, Mark {
109188e2f98eSSalyzyn, Mark 	/*
109288e2f98eSSalyzyn, Mark 	 *	This breaks array migration.
109388e2f98eSSalyzyn, Mark 	 */
109488e2f98eSSalyzyn, Mark 	return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
109588e2f98eSSalyzyn, Mark 			le32_to_cpu(dev->adapter_info.serial[0]), cid);
109688e2f98eSSalyzyn, Mark }
109788e2f98eSSalyzyn, Mark 
10988e31e607SSalyzyn, Mark static inline void set_sense(struct sense_data *sense_data, u8 sense_key,
10998e31e607SSalyzyn, Mark 	u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer)
11001da177e4SLinus Torvalds {
11018e31e607SSalyzyn, Mark 	u8 *sense_buf = (u8 *)sense_data;
11028e31e607SSalyzyn, Mark 	/* Sense data valid, err code 70h */
11038e31e607SSalyzyn, Mark 	sense_buf[0] = 0x70; /* No info field */
11041da177e4SLinus Torvalds 	sense_buf[1] = 0;	/* Segment number, always zero */
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds 	sense_buf[2] = sense_key;	/* Sense key */
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 	sense_buf[12] = sense_code;	/* Additional sense code */
11091da177e4SLinus Torvalds 	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */
11108e31e607SSalyzyn, Mark 
11111da177e4SLinus Torvalds 	if (sense_key == ILLEGAL_REQUEST) {
11128e31e607SSalyzyn, Mark 		sense_buf[7] = 10;	/* Additional sense length */
11131da177e4SLinus Torvalds 
11148e31e607SSalyzyn, Mark 		sense_buf[15] = bit_pointer;
11151da177e4SLinus Torvalds 		/* Illegal parameter is in the parameter block */
11161da177e4SLinus Torvalds 		if (sense_code == SENCODE_INVALID_CDB_FIELD)
11178e31e607SSalyzyn, Mark 			sense_buf[15] |= 0xc0;/* Std sense key specific field */
11181da177e4SLinus Torvalds 		/* Illegal parameter is in the CDB block */
11191da177e4SLinus Torvalds 		sense_buf[16] = field_pointer >> 8;	/* MSB */
11201da177e4SLinus Torvalds 		sense_buf[17] = field_pointer;		/* LSB */
11218e31e607SSalyzyn, Mark 	} else
11228e31e607SSalyzyn, Mark 		sense_buf[7] = 6;	/* Additional sense length */
11231da177e4SLinus Torvalds }
11241da177e4SLinus Torvalds 
1125e8f32de5SMark Haverkamp static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
1126e8f32de5SMark Haverkamp {
1127e8f32de5SMark Haverkamp 	if (lba & 0xffffffff00000000LL) {
1128e8f32de5SMark Haverkamp 		int cid = scmd_id(cmd);
1129e8f32de5SMark Haverkamp 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
1130e8f32de5SMark Haverkamp 		cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1131e8f32de5SMark Haverkamp 			SAM_STAT_CHECK_CONDITION;
11328e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
11338e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
11348e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
1135e8f32de5SMark Haverkamp 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
11363ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
11373ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
1138e8f32de5SMark Haverkamp 		cmd->scsi_done(cmd);
1139e8f32de5SMark Haverkamp 		return 1;
1140e8f32de5SMark Haverkamp 	}
1141e8f32de5SMark Haverkamp 	return 0;
1142e8f32de5SMark Haverkamp }
1143e8f32de5SMark Haverkamp 
1144e8f32de5SMark Haverkamp static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
1145e8f32de5SMark Haverkamp {
1146e8f32de5SMark Haverkamp 	return 0;
1147e8f32de5SMark Haverkamp }
1148e8f32de5SMark Haverkamp 
1149e8f32de5SMark Haverkamp static void io_callback(void *context, struct fib * fibptr);
1150e8f32de5SMark Haverkamp 
1151e8f32de5SMark Haverkamp static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1152e8f32de5SMark Haverkamp {
115385d22bbfSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
115485d22bbfSMahesh Rajashekhara 	u16 fibsize, command;
11550b433447SMahesh Rajashekhara 	long ret;
115685d22bbfSMahesh Rajashekhara 
1157e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1158d1ef4da8SRaghava Aditya Renukunta 	if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
1159d1ef4da8SRaghava Aditya Renukunta 		dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) &&
1160d1ef4da8SRaghava Aditya Renukunta 		!dev->sync_mode) {
116185d22bbfSMahesh Rajashekhara 		struct aac_raw_io2 *readcmd2;
116285d22bbfSMahesh Rajashekhara 		readcmd2 = (struct aac_raw_io2 *) fib_data(fib);
116385d22bbfSMahesh Rajashekhara 		memset(readcmd2, 0, sizeof(struct aac_raw_io2));
116485d22bbfSMahesh Rajashekhara 		readcmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff));
116585d22bbfSMahesh Rajashekhara 		readcmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1166b836439fSMahesh Rajashekhara 		readcmd2->byteCount = cpu_to_le32(count *
1167b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
116885d22bbfSMahesh Rajashekhara 		readcmd2->cid = cpu_to_le16(scmd_id(cmd));
116985d22bbfSMahesh Rajashekhara 		readcmd2->flags = cpu_to_le16(RIO2_IO_TYPE_READ);
11700b433447SMahesh Rajashekhara 		ret = aac_build_sgraw2(cmd, readcmd2,
11710b433447SMahesh Rajashekhara 				dev->scsi_host_ptr->sg_tablesize);
11720b433447SMahesh Rajashekhara 		if (ret < 0)
11730b433447SMahesh Rajashekhara 			return ret;
117485d22bbfSMahesh Rajashekhara 		command = ContainerRawIo2;
117585d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io2) +
117685d22bbfSMahesh Rajashekhara 			((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
117785d22bbfSMahesh Rajashekhara 	} else {
117885d22bbfSMahesh Rajashekhara 		struct aac_raw_io *readcmd;
1179e8f32de5SMark Haverkamp 		readcmd = (struct aac_raw_io *) fib_data(fib);
1180e8f32de5SMark Haverkamp 		readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
1181e8f32de5SMark Haverkamp 		readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1182b836439fSMahesh Rajashekhara 		readcmd->count = cpu_to_le32(count *
1183b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
1184e8f32de5SMark Haverkamp 		readcmd->cid = cpu_to_le16(scmd_id(cmd));
118585d22bbfSMahesh Rajashekhara 		readcmd->flags = cpu_to_le16(RIO_TYPE_READ);
1186e8f32de5SMark Haverkamp 		readcmd->bpTotal = 0;
1187e8f32de5SMark Haverkamp 		readcmd->bpComplete = 0;
11880b433447SMahesh Rajashekhara 		ret = aac_build_sgraw(cmd, &readcmd->sg);
11890b433447SMahesh Rajashekhara 		if (ret < 0)
11900b433447SMahesh Rajashekhara 			return ret;
119185d22bbfSMahesh Rajashekhara 		command = ContainerRawIo;
119285d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io) +
119385d22bbfSMahesh Rajashekhara 			((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw));
119485d22bbfSMahesh Rajashekhara 	}
119585d22bbfSMahesh Rajashekhara 
1196e8f32de5SMark Haverkamp 	BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
1197e8f32de5SMark Haverkamp 	/*
1198e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1199e8f32de5SMark Haverkamp 	 */
120085d22bbfSMahesh Rajashekhara 	return aac_fib_send(command,
1201e8f32de5SMark Haverkamp 			  fib,
1202e8f32de5SMark Haverkamp 			  fibsize,
1203e8f32de5SMark Haverkamp 			  FsaNormal,
1204e8f32de5SMark Haverkamp 			  0, 1,
1205e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1206e8f32de5SMark Haverkamp 			  (void *) cmd);
1207e8f32de5SMark Haverkamp }
1208e8f32de5SMark Haverkamp 
1209e8f32de5SMark Haverkamp static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1210e8f32de5SMark Haverkamp {
1211e8f32de5SMark Haverkamp 	u16 fibsize;
1212e8f32de5SMark Haverkamp 	struct aac_read64 *readcmd;
12130b433447SMahesh Rajashekhara 	long ret;
12140b433447SMahesh Rajashekhara 
1215e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1216e8f32de5SMark Haverkamp 	readcmd = (struct aac_read64 *) fib_data(fib);
1217e8f32de5SMark Haverkamp 	readcmd->command = cpu_to_le32(VM_CtHostRead64);
1218e8f32de5SMark Haverkamp 	readcmd->cid = cpu_to_le16(scmd_id(cmd));
1219e8f32de5SMark Haverkamp 	readcmd->sector_count = cpu_to_le16(count);
1220e8f32de5SMark Haverkamp 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1221e8f32de5SMark Haverkamp 	readcmd->pad   = 0;
1222e8f32de5SMark Haverkamp 	readcmd->flags = 0;
1223e8f32de5SMark Haverkamp 
12240b433447SMahesh Rajashekhara 	ret = aac_build_sg64(cmd, &readcmd->sg);
12250b433447SMahesh Rajashekhara 	if (ret < 0)
12260b433447SMahesh Rajashekhara 		return ret;
1227e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_read64) +
1228e8f32de5SMark Haverkamp 		((le32_to_cpu(readcmd->sg.count) - 1) *
1229e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1230e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1231e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1232e8f32de5SMark Haverkamp 	/*
1233e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1234e8f32de5SMark Haverkamp 	 */
1235e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand64,
1236e8f32de5SMark Haverkamp 			  fib,
1237e8f32de5SMark Haverkamp 			  fibsize,
1238e8f32de5SMark Haverkamp 			  FsaNormal,
1239e8f32de5SMark Haverkamp 			  0, 1,
1240e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1241e8f32de5SMark Haverkamp 			  (void *) cmd);
1242e8f32de5SMark Haverkamp }
1243e8f32de5SMark Haverkamp 
1244e8f32de5SMark Haverkamp static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1245e8f32de5SMark Haverkamp {
1246e8f32de5SMark Haverkamp 	u16 fibsize;
1247e8f32de5SMark Haverkamp 	struct aac_read *readcmd;
1248b836439fSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
12490b433447SMahesh Rajashekhara 	long ret;
12500b433447SMahesh Rajashekhara 
1251e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1252e8f32de5SMark Haverkamp 	readcmd = (struct aac_read *) fib_data(fib);
1253e8f32de5SMark Haverkamp 	readcmd->command = cpu_to_le32(VM_CtBlockRead);
1254f3307f72SChristoph Hellwig 	readcmd->cid = cpu_to_le32(scmd_id(cmd));
1255e8f32de5SMark Haverkamp 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1256b836439fSMahesh Rajashekhara 	readcmd->count = cpu_to_le32(count *
1257b836439fSMahesh Rajashekhara 		dev->fsa_dev[scmd_id(cmd)].block_size);
1258e8f32de5SMark Haverkamp 
12590b433447SMahesh Rajashekhara 	ret = aac_build_sg(cmd, &readcmd->sg);
12600b433447SMahesh Rajashekhara 	if (ret < 0)
12610b433447SMahesh Rajashekhara 		return ret;
1262e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_read) +
1263e8f32de5SMark Haverkamp 			((le32_to_cpu(readcmd->sg.count) - 1) *
1264e8f32de5SMark Haverkamp 			 sizeof (struct sgentry));
1265e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1266e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1267e8f32de5SMark Haverkamp 	/*
1268e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1269e8f32de5SMark Haverkamp 	 */
1270e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand,
1271e8f32de5SMark Haverkamp 			  fib,
1272e8f32de5SMark Haverkamp 			  fibsize,
1273e8f32de5SMark Haverkamp 			  FsaNormal,
1274e8f32de5SMark Haverkamp 			  0, 1,
1275e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1276e8f32de5SMark Haverkamp 			  (void *) cmd);
1277e8f32de5SMark Haverkamp }
1278e8f32de5SMark Haverkamp 
12799d399cc7SSalyzyn, Mark static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1280e8f32de5SMark Haverkamp {
128185d22bbfSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
128285d22bbfSMahesh Rajashekhara 	u16 fibsize, command;
12830b433447SMahesh Rajashekhara 	long ret;
128485d22bbfSMahesh Rajashekhara 
1285e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1286d1ef4da8SRaghava Aditya Renukunta 	if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
1287d1ef4da8SRaghava Aditya Renukunta 		dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) &&
1288d1ef4da8SRaghava Aditya Renukunta 		!dev->sync_mode) {
128985d22bbfSMahesh Rajashekhara 		struct aac_raw_io2 *writecmd2;
129085d22bbfSMahesh Rajashekhara 		writecmd2 = (struct aac_raw_io2 *) fib_data(fib);
129185d22bbfSMahesh Rajashekhara 		memset(writecmd2, 0, sizeof(struct aac_raw_io2));
129285d22bbfSMahesh Rajashekhara 		writecmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff));
129385d22bbfSMahesh Rajashekhara 		writecmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1294b836439fSMahesh Rajashekhara 		writecmd2->byteCount = cpu_to_le32(count *
1295b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
129685d22bbfSMahesh Rajashekhara 		writecmd2->cid = cpu_to_le16(scmd_id(cmd));
129785d22bbfSMahesh Rajashekhara 		writecmd2->flags = (fua && ((aac_cache & 5) != 1) &&
129885d22bbfSMahesh Rajashekhara 						   (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
129985d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO2_IO_TYPE_WRITE|RIO2_IO_SUREWRITE) :
130085d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO2_IO_TYPE_WRITE);
13010b433447SMahesh Rajashekhara 		ret = aac_build_sgraw2(cmd, writecmd2,
13020b433447SMahesh Rajashekhara 				dev->scsi_host_ptr->sg_tablesize);
13030b433447SMahesh Rajashekhara 		if (ret < 0)
13040b433447SMahesh Rajashekhara 			return ret;
130585d22bbfSMahesh Rajashekhara 		command = ContainerRawIo2;
130685d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io2) +
130785d22bbfSMahesh Rajashekhara 			((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
130885d22bbfSMahesh Rajashekhara 	} else {
130985d22bbfSMahesh Rajashekhara 		struct aac_raw_io *writecmd;
1310e8f32de5SMark Haverkamp 		writecmd = (struct aac_raw_io *) fib_data(fib);
1311e8f32de5SMark Haverkamp 		writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
1312e8f32de5SMark Haverkamp 		writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1313b836439fSMahesh Rajashekhara 		writecmd->count = cpu_to_le32(count *
1314b836439fSMahesh Rajashekhara 			dev->fsa_dev[scmd_id(cmd)].block_size);
1315e8f32de5SMark Haverkamp 		writecmd->cid = cpu_to_le16(scmd_id(cmd));
131695e852e1SSalyzyn, Mark 		writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
131795e852e1SSalyzyn, Mark 						   (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
131885d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO_TYPE_WRITE|RIO_SUREWRITE) :
131985d22bbfSMahesh Rajashekhara 			cpu_to_le16(RIO_TYPE_WRITE);
1320e8f32de5SMark Haverkamp 		writecmd->bpTotal = 0;
1321e8f32de5SMark Haverkamp 		writecmd->bpComplete = 0;
13220b433447SMahesh Rajashekhara 		ret = aac_build_sgraw(cmd, &writecmd->sg);
13230b433447SMahesh Rajashekhara 		if (ret < 0)
13240b433447SMahesh Rajashekhara 			return ret;
132585d22bbfSMahesh Rajashekhara 		command = ContainerRawIo;
132685d22bbfSMahesh Rajashekhara 		fibsize = sizeof(struct aac_raw_io) +
132785d22bbfSMahesh Rajashekhara 			((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw));
132885d22bbfSMahesh Rajashekhara 	}
132985d22bbfSMahesh Rajashekhara 
1330e8f32de5SMark Haverkamp 	BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
1331e8f32de5SMark Haverkamp 	/*
1332e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1333e8f32de5SMark Haverkamp 	 */
133485d22bbfSMahesh Rajashekhara 	return aac_fib_send(command,
1335e8f32de5SMark Haverkamp 			  fib,
1336e8f32de5SMark Haverkamp 			  fibsize,
1337e8f32de5SMark Haverkamp 			  FsaNormal,
1338e8f32de5SMark Haverkamp 			  0, 1,
1339e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1340e8f32de5SMark Haverkamp 			  (void *) cmd);
1341e8f32de5SMark Haverkamp }
1342e8f32de5SMark Haverkamp 
13439d399cc7SSalyzyn, Mark static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1344e8f32de5SMark Haverkamp {
1345e8f32de5SMark Haverkamp 	u16 fibsize;
1346e8f32de5SMark Haverkamp 	struct aac_write64 *writecmd;
13470b433447SMahesh Rajashekhara 	long ret;
13480b433447SMahesh Rajashekhara 
1349e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1350e8f32de5SMark Haverkamp 	writecmd = (struct aac_write64 *) fib_data(fib);
1351e8f32de5SMark Haverkamp 	writecmd->command = cpu_to_le32(VM_CtHostWrite64);
1352e8f32de5SMark Haverkamp 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
1353e8f32de5SMark Haverkamp 	writecmd->sector_count = cpu_to_le16(count);
1354e8f32de5SMark Haverkamp 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1355e8f32de5SMark Haverkamp 	writecmd->pad	= 0;
1356e8f32de5SMark Haverkamp 	writecmd->flags	= 0;
1357e8f32de5SMark Haverkamp 
13580b433447SMahesh Rajashekhara 	ret = aac_build_sg64(cmd, &writecmd->sg);
13590b433447SMahesh Rajashekhara 	if (ret < 0)
13600b433447SMahesh Rajashekhara 		return ret;
1361e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_write64) +
1362e8f32de5SMark Haverkamp 		((le32_to_cpu(writecmd->sg.count) - 1) *
1363e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1364e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1365e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1366e8f32de5SMark Haverkamp 	/*
1367e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1368e8f32de5SMark Haverkamp 	 */
1369e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand64,
1370e8f32de5SMark Haverkamp 			  fib,
1371e8f32de5SMark Haverkamp 			  fibsize,
1372e8f32de5SMark Haverkamp 			  FsaNormal,
1373e8f32de5SMark Haverkamp 			  0, 1,
1374e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1375e8f32de5SMark Haverkamp 			  (void *) cmd);
1376e8f32de5SMark Haverkamp }
1377e8f32de5SMark Haverkamp 
13789d399cc7SSalyzyn, Mark static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1379e8f32de5SMark Haverkamp {
1380e8f32de5SMark Haverkamp 	u16 fibsize;
1381e8f32de5SMark Haverkamp 	struct aac_write *writecmd;
1382b836439fSMahesh Rajashekhara 	struct aac_dev *dev = fib->dev;
13830b433447SMahesh Rajashekhara 	long ret;
13840b433447SMahesh Rajashekhara 
1385e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1386e8f32de5SMark Haverkamp 	writecmd = (struct aac_write *) fib_data(fib);
1387e8f32de5SMark Haverkamp 	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
1388f3307f72SChristoph Hellwig 	writecmd->cid = cpu_to_le32(scmd_id(cmd));
1389e8f32de5SMark Haverkamp 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1390b836439fSMahesh Rajashekhara 	writecmd->count = cpu_to_le32(count *
1391b836439fSMahesh Rajashekhara 		dev->fsa_dev[scmd_id(cmd)].block_size);
1392e8f32de5SMark Haverkamp 	writecmd->sg.count = cpu_to_le32(1);
1393e8f32de5SMark Haverkamp 	/* ->stable is not used - it did mean which type of write */
1394e8f32de5SMark Haverkamp 
13950b433447SMahesh Rajashekhara 	ret = aac_build_sg(cmd, &writecmd->sg);
13960b433447SMahesh Rajashekhara 	if (ret < 0)
13970b433447SMahesh Rajashekhara 		return ret;
1398e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_write) +
1399e8f32de5SMark Haverkamp 		((le32_to_cpu(writecmd->sg.count) - 1) *
1400e8f32de5SMark Haverkamp 		 sizeof (struct sgentry));
1401e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1402e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1403e8f32de5SMark Haverkamp 	/*
1404e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1405e8f32de5SMark Haverkamp 	 */
1406e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand,
1407e8f32de5SMark Haverkamp 			  fib,
1408e8f32de5SMark Haverkamp 			  fibsize,
1409e8f32de5SMark Haverkamp 			  FsaNormal,
1410e8f32de5SMark Haverkamp 			  0, 1,
1411e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1412e8f32de5SMark Haverkamp 			  (void *) cmd);
1413e8f32de5SMark Haverkamp }
1414e8f32de5SMark Haverkamp 
1415e8f32de5SMark Haverkamp static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd)
1416e8f32de5SMark Haverkamp {
1417e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd;
1418e8f32de5SMark Haverkamp 	u32 flag;
1419e8f32de5SMark Haverkamp 	u32 timeout;
1420e8f32de5SMark Haverkamp 
1421e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1422e8f32de5SMark Haverkamp 	switch(cmd->sc_data_direction){
1423e8f32de5SMark Haverkamp 	case DMA_TO_DEVICE:
1424e8f32de5SMark Haverkamp 		flag = SRB_DataOut;
1425e8f32de5SMark Haverkamp 		break;
1426e8f32de5SMark Haverkamp 	case DMA_BIDIRECTIONAL:
1427e8f32de5SMark Haverkamp 		flag = SRB_DataIn | SRB_DataOut;
1428e8f32de5SMark Haverkamp 		break;
1429e8f32de5SMark Haverkamp 	case DMA_FROM_DEVICE:
1430e8f32de5SMark Haverkamp 		flag = SRB_DataIn;
1431e8f32de5SMark Haverkamp 		break;
1432e8f32de5SMark Haverkamp 	case DMA_NONE:
1433e8f32de5SMark Haverkamp 	default:	/* shuts up some versions of gcc */
1434e8f32de5SMark Haverkamp 		flag = SRB_NoDataXfer;
1435e8f32de5SMark Haverkamp 		break;
1436e8f32de5SMark Haverkamp 	}
1437e8f32de5SMark Haverkamp 
1438e8f32de5SMark Haverkamp 	srbcmd = (struct aac_srb*) fib_data(fib);
1439e8f32de5SMark Haverkamp 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
1440e8f32de5SMark Haverkamp 	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd)));
1441e8f32de5SMark Haverkamp 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
1442e8f32de5SMark Haverkamp 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
1443e8f32de5SMark Haverkamp 	srbcmd->flags    = cpu_to_le32(flag);
1444242f9dcbSJens Axboe 	timeout = cmd->request->timeout/HZ;
1445e8f32de5SMark Haverkamp 	if (timeout == 0)
1446e8f32de5SMark Haverkamp 		timeout = 1;
1447e8f32de5SMark Haverkamp 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
1448e8f32de5SMark Haverkamp 	srbcmd->retry_limit = 0; /* Obsolete parameter */
1449e8f32de5SMark Haverkamp 	srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len);
1450e8f32de5SMark Haverkamp 	return srbcmd;
1451e8f32de5SMark Haverkamp }
1452e8f32de5SMark Haverkamp 
1453ab5d129fSRaghava Aditya Renukunta static struct aac_hba_cmd_req *aac_construct_hbacmd(struct fib *fib,
1454ab5d129fSRaghava Aditya Renukunta 							struct scsi_cmnd *cmd)
1455ab5d129fSRaghava Aditya Renukunta {
1456ab5d129fSRaghava Aditya Renukunta 	struct aac_hba_cmd_req *hbacmd;
1457ab5d129fSRaghava Aditya Renukunta 	struct aac_dev *dev;
1458ab5d129fSRaghava Aditya Renukunta 	int bus, target;
1459ab5d129fSRaghava Aditya Renukunta 	u64 address;
1460ab5d129fSRaghava Aditya Renukunta 
1461ab5d129fSRaghava Aditya Renukunta 	dev = (struct aac_dev *)cmd->device->host->hostdata;
1462ab5d129fSRaghava Aditya Renukunta 
1463ab5d129fSRaghava Aditya Renukunta 	hbacmd = (struct aac_hba_cmd_req *)fib->hw_fib_va;
1464ab5d129fSRaghava Aditya Renukunta 	memset(hbacmd, 0, 96);	/* sizeof(*hbacmd) is not necessary */
1465ab5d129fSRaghava Aditya Renukunta 	/* iu_type is a parameter of aac_hba_send */
1466ab5d129fSRaghava Aditya Renukunta 	switch (cmd->sc_data_direction) {
1467ab5d129fSRaghava Aditya Renukunta 	case DMA_TO_DEVICE:
1468ab5d129fSRaghava Aditya Renukunta 		hbacmd->byte1 = 2;
1469ab5d129fSRaghava Aditya Renukunta 		break;
1470ab5d129fSRaghava Aditya Renukunta 	case DMA_FROM_DEVICE:
1471ab5d129fSRaghava Aditya Renukunta 	case DMA_BIDIRECTIONAL:
1472ab5d129fSRaghava Aditya Renukunta 		hbacmd->byte1 = 1;
1473ab5d129fSRaghava Aditya Renukunta 		break;
1474ab5d129fSRaghava Aditya Renukunta 	case DMA_NONE:
1475ab5d129fSRaghava Aditya Renukunta 	default:
1476ab5d129fSRaghava Aditya Renukunta 		break;
1477ab5d129fSRaghava Aditya Renukunta 	}
1478ab5d129fSRaghava Aditya Renukunta 	hbacmd->lun[1] = cpu_to_le32(cmd->device->lun);
1479ab5d129fSRaghava Aditya Renukunta 
1480ab5d129fSRaghava Aditya Renukunta 	bus = aac_logical_to_phys(scmd_channel(cmd));
1481ab5d129fSRaghava Aditya Renukunta 	target = scmd_id(cmd);
1482ab5d129fSRaghava Aditya Renukunta 	hbacmd->it_nexus = dev->hba_map[bus][target].rmw_nexus;
1483ab5d129fSRaghava Aditya Renukunta 
1484ab5d129fSRaghava Aditya Renukunta 	/* we fill in reply_qid later in aac_src_deliver_message */
1485ab5d129fSRaghava Aditya Renukunta 	/* we fill in iu_type, request_id later in aac_hba_send */
1486ab5d129fSRaghava Aditya Renukunta 	/* we fill in emb_data_desc_count later in aac_build_sghba */
1487ab5d129fSRaghava Aditya Renukunta 
1488ab5d129fSRaghava Aditya Renukunta 	memcpy(hbacmd->cdb, cmd->cmnd, cmd->cmd_len);
1489ab5d129fSRaghava Aditya Renukunta 	hbacmd->data_length = cpu_to_le32(scsi_bufflen(cmd));
1490ab5d129fSRaghava Aditya Renukunta 
1491ab5d129fSRaghava Aditya Renukunta 	address = (u64)fib->hw_error_pa;
1492ab5d129fSRaghava Aditya Renukunta 	hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32));
1493ab5d129fSRaghava Aditya Renukunta 	hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff));
1494ab5d129fSRaghava Aditya Renukunta 	hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE);
1495ab5d129fSRaghava Aditya Renukunta 
1496ab5d129fSRaghava Aditya Renukunta 	return hbacmd;
1497ab5d129fSRaghava Aditya Renukunta }
1498ab5d129fSRaghava Aditya Renukunta 
1499e8f32de5SMark Haverkamp static void aac_srb_callback(void *context, struct fib * fibptr);
1500e8f32de5SMark Haverkamp 
1501e8f32de5SMark Haverkamp static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
1502e8f32de5SMark Haverkamp {
1503e8f32de5SMark Haverkamp 	u16 fibsize;
1504e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
15050b433447SMahesh Rajashekhara 	long ret;
1506e8f32de5SMark Haverkamp 
15070b433447SMahesh Rajashekhara 	ret = aac_build_sg64(cmd, (struct sgmap64 *) &srbcmd->sg);
15080b433447SMahesh Rajashekhara 	if (ret < 0)
15090b433447SMahesh Rajashekhara 		return ret;
1510727eead6SFUJITA Tomonori 	srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
1511e8f32de5SMark Haverkamp 
1512e8f32de5SMark Haverkamp 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1513e8f32de5SMark Haverkamp 	memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
1514e8f32de5SMark Haverkamp 	/*
1515e8f32de5SMark Haverkamp 	 *	Build Scatter/Gather list
1516e8f32de5SMark Haverkamp 	 */
1517e8f32de5SMark Haverkamp 	fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
1518e8f32de5SMark Haverkamp 		((le32_to_cpu(srbcmd->sg.count) & 0xff) *
1519e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1520e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1521e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1522e8f32de5SMark Haverkamp 
1523e8f32de5SMark Haverkamp 	/*
1524e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1525e8f32de5SMark Haverkamp 	 */
1526e8f32de5SMark Haverkamp 	return aac_fib_send(ScsiPortCommand64, fib,
1527e8f32de5SMark Haverkamp 				fibsize, FsaNormal, 0, 1,
1528e8f32de5SMark Haverkamp 				  (fib_callback) aac_srb_callback,
1529e8f32de5SMark Haverkamp 				  (void *) cmd);
1530e8f32de5SMark Haverkamp }
1531e8f32de5SMark Haverkamp 
1532e8f32de5SMark Haverkamp static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
1533e8f32de5SMark Haverkamp {
1534e8f32de5SMark Haverkamp 	u16 fibsize;
1535e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
15360b433447SMahesh Rajashekhara 	long ret;
1537e8f32de5SMark Haverkamp 
15380b433447SMahesh Rajashekhara 	ret = aac_build_sg(cmd, (struct sgmap *)&srbcmd->sg);
15390b433447SMahesh Rajashekhara 	if (ret < 0)
15400b433447SMahesh Rajashekhara 		return ret;
1541727eead6SFUJITA Tomonori 	srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
1542e8f32de5SMark Haverkamp 
1543e8f32de5SMark Haverkamp 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1544e8f32de5SMark Haverkamp 	memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
1545e8f32de5SMark Haverkamp 	/*
1546e8f32de5SMark Haverkamp 	 *	Build Scatter/Gather list
1547e8f32de5SMark Haverkamp 	 */
1548e8f32de5SMark Haverkamp 	fibsize = sizeof (struct aac_srb) +
1549e8f32de5SMark Haverkamp 		(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
1550e8f32de5SMark Haverkamp 		 sizeof (struct sgentry));
1551e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1552e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1553e8f32de5SMark Haverkamp 
1554e8f32de5SMark Haverkamp 	/*
1555e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1556e8f32de5SMark Haverkamp 	 */
1557e8f32de5SMark Haverkamp 	return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1,
1558e8f32de5SMark Haverkamp 				  (fib_callback) aac_srb_callback, (void *) cmd);
1559e8f32de5SMark Haverkamp }
1560e8f32de5SMark Haverkamp 
156194cf6ba1SSalyzyn, Mark static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
156294cf6ba1SSalyzyn, Mark {
1563d8e96507SLeubner, Achim 	if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac &&
156494cf6ba1SSalyzyn, Mark 	    (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
156594cf6ba1SSalyzyn, Mark 		return FAILED;
156694cf6ba1SSalyzyn, Mark 	return aac_scsi_32(fib, cmd);
156794cf6ba1SSalyzyn, Mark }
156894cf6ba1SSalyzyn, Mark 
1569ab5d129fSRaghava Aditya Renukunta static int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd)
1570ab5d129fSRaghava Aditya Renukunta {
1571ab5d129fSRaghava Aditya Renukunta 	struct aac_hba_cmd_req *hbacmd = aac_construct_hbacmd(fib, cmd);
1572ab5d129fSRaghava Aditya Renukunta 	struct aac_dev *dev;
1573ab5d129fSRaghava Aditya Renukunta 	long ret;
1574ab5d129fSRaghava Aditya Renukunta 
1575ab5d129fSRaghava Aditya Renukunta 	dev = (struct aac_dev *)cmd->device->host->hostdata;
1576ab5d129fSRaghava Aditya Renukunta 
1577ab5d129fSRaghava Aditya Renukunta 	ret = aac_build_sghba(cmd, hbacmd,
1578ab5d129fSRaghava Aditya Renukunta 		dev->scsi_host_ptr->sg_tablesize, (u64)fib->hw_sgl_pa);
1579ab5d129fSRaghava Aditya Renukunta 	if (ret < 0)
1580ab5d129fSRaghava Aditya Renukunta 		return ret;
1581ab5d129fSRaghava Aditya Renukunta 
1582ab5d129fSRaghava Aditya Renukunta 	/*
1583ab5d129fSRaghava Aditya Renukunta 	 *	Now send the HBA command to the adapter
1584ab5d129fSRaghava Aditya Renukunta 	 */
1585ab5d129fSRaghava Aditya Renukunta 	fib->hbacmd_size = 64 + le32_to_cpu(hbacmd->emb_data_desc_count) *
1586ab5d129fSRaghava Aditya Renukunta 		sizeof(struct aac_hba_sgl);
1587ab5d129fSRaghava Aditya Renukunta 
1588ab5d129fSRaghava Aditya Renukunta 	return aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, fib,
1589ab5d129fSRaghava Aditya Renukunta 				  (fib_callback) aac_hba_callback,
1590ab5d129fSRaghava Aditya Renukunta 				  (void *) cmd);
1591ab5d129fSRaghava Aditya Renukunta }
1592ab5d129fSRaghava Aditya Renukunta 
159371a91ca4SRaghava Aditya Renukunta int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target)
159471a91ca4SRaghava Aditya Renukunta {
159571a91ca4SRaghava Aditya Renukunta 	struct fib *fibptr;
159671a91ca4SRaghava Aditya Renukunta 	struct aac_srb *srbcmd;
159771a91ca4SRaghava Aditya Renukunta 	struct sgmap64 *sg64;
159871a91ca4SRaghava Aditya Renukunta 	struct aac_ciss_identify_pd *identify_resp;
159971a91ca4SRaghava Aditya Renukunta 	dma_addr_t addr;
160071a91ca4SRaghava Aditya Renukunta 	u32 vbus, vid;
160171a91ca4SRaghava Aditya Renukunta 	u16 fibsize, datasize;
160271a91ca4SRaghava Aditya Renukunta 	int rcode = -ENOMEM;
160371a91ca4SRaghava Aditya Renukunta 
1604ab5d129fSRaghava Aditya Renukunta 
160571a91ca4SRaghava Aditya Renukunta 	fibptr = aac_fib_alloc(dev);
160671a91ca4SRaghava Aditya Renukunta 	if (!fibptr)
160771a91ca4SRaghava Aditya Renukunta 		goto out;
160871a91ca4SRaghava Aditya Renukunta 
160971a91ca4SRaghava Aditya Renukunta 	fibsize = sizeof(struct aac_srb) -
161071a91ca4SRaghava Aditya Renukunta 			sizeof(struct sgentry) + sizeof(struct sgentry64);
161171a91ca4SRaghava Aditya Renukunta 	datasize = sizeof(struct aac_ciss_identify_pd);
161271a91ca4SRaghava Aditya Renukunta 
161371a91ca4SRaghava Aditya Renukunta 	identify_resp =  pci_alloc_consistent(dev->pdev, datasize, &addr);
161471a91ca4SRaghava Aditya Renukunta 
161571a91ca4SRaghava Aditya Renukunta 	if (!identify_resp)
161671a91ca4SRaghava Aditya Renukunta 		goto fib_free_ptr;
161771a91ca4SRaghava Aditya Renukunta 
161871a91ca4SRaghava Aditya Renukunta 	vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceBus);
161971a91ca4SRaghava Aditya Renukunta 	vid = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceTarget);
162071a91ca4SRaghava Aditya Renukunta 
162171a91ca4SRaghava Aditya Renukunta 	aac_fib_init(fibptr);
162271a91ca4SRaghava Aditya Renukunta 
162371a91ca4SRaghava Aditya Renukunta 	srbcmd = (struct aac_srb *) fib_data(fibptr);
162471a91ca4SRaghava Aditya Renukunta 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
162571a91ca4SRaghava Aditya Renukunta 	srbcmd->channel  = cpu_to_le32(vbus);
162671a91ca4SRaghava Aditya Renukunta 	srbcmd->id       = cpu_to_le32(vid);
162771a91ca4SRaghava Aditya Renukunta 	srbcmd->lun      = 0;
162871a91ca4SRaghava Aditya Renukunta 	srbcmd->flags    = cpu_to_le32(SRB_DataIn);
162971a91ca4SRaghava Aditya Renukunta 	srbcmd->timeout  = cpu_to_le32(10);
163071a91ca4SRaghava Aditya Renukunta 	srbcmd->retry_limit = 0;
163171a91ca4SRaghava Aditya Renukunta 	srbcmd->cdb_size = cpu_to_le32(12);
163271a91ca4SRaghava Aditya Renukunta 	srbcmd->count = cpu_to_le32(datasize);
163371a91ca4SRaghava Aditya Renukunta 
163471a91ca4SRaghava Aditya Renukunta 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
163571a91ca4SRaghava Aditya Renukunta 	srbcmd->cdb[0] = 0x26;
163671a91ca4SRaghava Aditya Renukunta 	srbcmd->cdb[2] = (u8)((AAC_MAX_LUN + target) & 0x00FF);
163771a91ca4SRaghava Aditya Renukunta 	srbcmd->cdb[6] = CISS_IDENTIFY_PHYSICAL_DEVICE;
163871a91ca4SRaghava Aditya Renukunta 
163971a91ca4SRaghava Aditya Renukunta 	sg64 = (struct sgmap64 *)&srbcmd->sg;
164071a91ca4SRaghava Aditya Renukunta 	sg64->count = cpu_to_le32(1);
164171a91ca4SRaghava Aditya Renukunta 	sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16));
164271a91ca4SRaghava Aditya Renukunta 	sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
164371a91ca4SRaghava Aditya Renukunta 	sg64->sg[0].count = cpu_to_le32(datasize);
164471a91ca4SRaghava Aditya Renukunta 
164571a91ca4SRaghava Aditya Renukunta 	rcode = aac_fib_send(ScsiPortCommand64,
164671a91ca4SRaghava Aditya Renukunta 		fibptr, fibsize, FsaNormal, 1, 1, NULL, NULL);
164771a91ca4SRaghava Aditya Renukunta 
164871a91ca4SRaghava Aditya Renukunta 	if (identify_resp->current_queue_depth_limit <= 0 ||
164971a91ca4SRaghava Aditya Renukunta 		identify_resp->current_queue_depth_limit > 32)
165071a91ca4SRaghava Aditya Renukunta 		dev->hba_map[bus][target].qd_limit = 32;
165171a91ca4SRaghava Aditya Renukunta 	else
165271a91ca4SRaghava Aditya Renukunta 		dev->hba_map[bus][target].qd_limit =
165371a91ca4SRaghava Aditya Renukunta 			identify_resp->current_queue_depth_limit;
165471a91ca4SRaghava Aditya Renukunta 
165571a91ca4SRaghava Aditya Renukunta 	pci_free_consistent(dev->pdev, datasize, (void *)identify_resp, addr);
165671a91ca4SRaghava Aditya Renukunta 
165771a91ca4SRaghava Aditya Renukunta 	aac_fib_complete(fibptr);
165871a91ca4SRaghava Aditya Renukunta 
165971a91ca4SRaghava Aditya Renukunta fib_free_ptr:
166071a91ca4SRaghava Aditya Renukunta 	aac_fib_free(fibptr);
166171a91ca4SRaghava Aditya Renukunta out:
166271a91ca4SRaghava Aditya Renukunta 	return rcode;
166371a91ca4SRaghava Aditya Renukunta }
166471a91ca4SRaghava Aditya Renukunta 
1665c83b11e3SRaghava Aditya Renukunta /**
1666c83b11e3SRaghava Aditya Renukunta  *	aac_update hba_map()-	update current hba map with data from FW
1667c83b11e3SRaghava Aditya Renukunta  *	@dev:	aac_dev structure
1668c83b11e3SRaghava Aditya Renukunta  *	@phys_luns: FW information from report phys luns
1669c83b11e3SRaghava Aditya Renukunta  *
1670c83b11e3SRaghava Aditya Renukunta  *	Update our hba map with the information gathered from the FW
1671c83b11e3SRaghava Aditya Renukunta  */
1672c83b11e3SRaghava Aditya Renukunta void aac_update_hba_map(struct aac_dev *dev,
16736223a39fSRaghava Aditya Renukunta 		struct aac_ciss_phys_luns_resp *phys_luns, int rescan)
1674c83b11e3SRaghava Aditya Renukunta {
1675c83b11e3SRaghava Aditya Renukunta 	/* ok and extended reporting */
1676c83b11e3SRaghava Aditya Renukunta 	u32 lun_count, nexus;
1677c83b11e3SRaghava Aditya Renukunta 	u32 i, bus, target;
1678c83b11e3SRaghava Aditya Renukunta 	u8 expose_flag, attribs;
1679c83b11e3SRaghava Aditya Renukunta 	u8 devtype;
1680c83b11e3SRaghava Aditya Renukunta 
1681c83b11e3SRaghava Aditya Renukunta 	lun_count = ((phys_luns->list_length[0] << 24)
1682c83b11e3SRaghava Aditya Renukunta 			+ (phys_luns->list_length[1] << 16)
1683c83b11e3SRaghava Aditya Renukunta 			+ (phys_luns->list_length[2] << 8)
1684c83b11e3SRaghava Aditya Renukunta 			+ (phys_luns->list_length[3])) / 24;
1685c83b11e3SRaghava Aditya Renukunta 
1686c83b11e3SRaghava Aditya Renukunta 	for (i = 0; i < lun_count; ++i) {
1687c83b11e3SRaghava Aditya Renukunta 
1688c83b11e3SRaghava Aditya Renukunta 		bus = phys_luns->lun[i].level2[1] & 0x3f;
1689c83b11e3SRaghava Aditya Renukunta 		target = phys_luns->lun[i].level2[0];
1690c83b11e3SRaghava Aditya Renukunta 		expose_flag = phys_luns->lun[i].bus >> 6;
1691c83b11e3SRaghava Aditya Renukunta 		attribs = phys_luns->lun[i].node_ident[9];
1692c83b11e3SRaghava Aditya Renukunta 		nexus = *((u32 *) &phys_luns->lun[i].node_ident[12]);
1693c83b11e3SRaghava Aditya Renukunta 
1694c83b11e3SRaghava Aditya Renukunta 		if (bus >= AAC_MAX_BUSES || target >= AAC_MAX_TARGETS)
1695c83b11e3SRaghava Aditya Renukunta 			continue;
1696c83b11e3SRaghava Aditya Renukunta 
1697c83b11e3SRaghava Aditya Renukunta 		dev->hba_map[bus][target].expose = expose_flag;
1698c83b11e3SRaghava Aditya Renukunta 
1699c83b11e3SRaghava Aditya Renukunta 		if (expose_flag != 0) {
1700c83b11e3SRaghava Aditya Renukunta 			devtype = AAC_DEVTYPE_RAID_MEMBER;
1701c83b11e3SRaghava Aditya Renukunta 			goto update_devtype;
1702c83b11e3SRaghava Aditya Renukunta 		}
1703c83b11e3SRaghava Aditya Renukunta 
1704c83b11e3SRaghava Aditya Renukunta 		if (nexus != 0 && (attribs & 8)) {
1705c83b11e3SRaghava Aditya Renukunta 			devtype = AAC_DEVTYPE_NATIVE_RAW;
1706c83b11e3SRaghava Aditya Renukunta 			dev->hba_map[bus][target].rmw_nexus =
1707c83b11e3SRaghava Aditya Renukunta 					nexus;
1708c83b11e3SRaghava Aditya Renukunta 		} else
1709c83b11e3SRaghava Aditya Renukunta 			devtype = AAC_DEVTYPE_ARC_RAW;
1710c83b11e3SRaghava Aditya Renukunta 
1711c83b11e3SRaghava Aditya Renukunta 		if (devtype != AAC_DEVTYPE_NATIVE_RAW)
1712c83b11e3SRaghava Aditya Renukunta 			goto update_devtype;
1713c83b11e3SRaghava Aditya Renukunta 
171471a91ca4SRaghava Aditya Renukunta 		if (aac_issue_bmic_identify(dev, bus, target) < 0)
171571a91ca4SRaghava Aditya Renukunta 			dev->hba_map[bus][target].qd_limit = 32;
171671a91ca4SRaghava Aditya Renukunta 
1717c83b11e3SRaghava Aditya Renukunta update_devtype:
17186223a39fSRaghava Aditya Renukunta 		if (rescan == AAC_INIT)
1719c83b11e3SRaghava Aditya Renukunta 			dev->hba_map[bus][target].devtype = devtype;
17206223a39fSRaghava Aditya Renukunta 		else
17216223a39fSRaghava Aditya Renukunta 			dev->hba_map[bus][target].new_devtype = devtype;
1722c83b11e3SRaghava Aditya Renukunta 	}
1723c83b11e3SRaghava Aditya Renukunta }
1724c83b11e3SRaghava Aditya Renukunta 
1725c83b11e3SRaghava Aditya Renukunta /**
1726c83b11e3SRaghava Aditya Renukunta  *	aac_report_phys_luns()	Process topology change
1727c83b11e3SRaghava Aditya Renukunta  *	@dev:		aac_dev structure
1728c83b11e3SRaghava Aditya Renukunta  *	@fibptr:	fib pointer
1729c83b11e3SRaghava Aditya Renukunta  *
1730c83b11e3SRaghava Aditya Renukunta  *	Execute a CISS REPORT PHYS LUNS and process the results into
1731c83b11e3SRaghava Aditya Renukunta  *	the current hba_map.
1732c83b11e3SRaghava Aditya Renukunta  */
17336223a39fSRaghava Aditya Renukunta int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan)
1734c83b11e3SRaghava Aditya Renukunta {
1735c83b11e3SRaghava Aditya Renukunta 	int fibsize, datasize;
1736c83b11e3SRaghava Aditya Renukunta 	struct aac_ciss_phys_luns_resp *phys_luns;
1737c83b11e3SRaghava Aditya Renukunta 	struct aac_srb *srbcmd;
1738c83b11e3SRaghava Aditya Renukunta 	struct sgmap64 *sg64;
1739c83b11e3SRaghava Aditya Renukunta 	dma_addr_t addr;
1740c83b11e3SRaghava Aditya Renukunta 	u32 vbus, vid;
1741c83b11e3SRaghava Aditya Renukunta 	u32 rcode = 0;
1742c83b11e3SRaghava Aditya Renukunta 
1743c83b11e3SRaghava Aditya Renukunta 	/* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
1744c83b11e3SRaghava Aditya Renukunta 	fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry)
1745c83b11e3SRaghava Aditya Renukunta 			+ sizeof(struct sgentry64);
1746c83b11e3SRaghava Aditya Renukunta 	datasize = sizeof(struct aac_ciss_phys_luns_resp)
1747c83b11e3SRaghava Aditya Renukunta 			+ (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun);
1748c83b11e3SRaghava Aditya Renukunta 
1749c83b11e3SRaghava Aditya Renukunta 	phys_luns = (struct aac_ciss_phys_luns_resp *) pci_alloc_consistent(
1750c83b11e3SRaghava Aditya Renukunta 			dev->pdev, datasize, &addr);
1751c83b11e3SRaghava Aditya Renukunta 
1752c83b11e3SRaghava Aditya Renukunta 	if (phys_luns == NULL) {
1753c83b11e3SRaghava Aditya Renukunta 		rcode = -ENOMEM;
1754c83b11e3SRaghava Aditya Renukunta 		goto err_out;
1755c83b11e3SRaghava Aditya Renukunta 	}
1756c83b11e3SRaghava Aditya Renukunta 
1757c83b11e3SRaghava Aditya Renukunta 	vbus = (u32) le16_to_cpu(
1758c83b11e3SRaghava Aditya Renukunta 			dev->supplement_adapter_info.VirtDeviceBus);
1759c83b11e3SRaghava Aditya Renukunta 	vid = (u32) le16_to_cpu(
1760c83b11e3SRaghava Aditya Renukunta 			dev->supplement_adapter_info.VirtDeviceTarget);
1761c83b11e3SRaghava Aditya Renukunta 
1762c83b11e3SRaghava Aditya Renukunta 	aac_fib_init(fibptr);
1763c83b11e3SRaghava Aditya Renukunta 
1764c83b11e3SRaghava Aditya Renukunta 	srbcmd = (struct aac_srb *) fib_data(fibptr);
1765c83b11e3SRaghava Aditya Renukunta 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
1766c83b11e3SRaghava Aditya Renukunta 	srbcmd->channel = cpu_to_le32(vbus);
1767c83b11e3SRaghava Aditya Renukunta 	srbcmd->id = cpu_to_le32(vid);
1768c83b11e3SRaghava Aditya Renukunta 	srbcmd->lun = 0;
1769c83b11e3SRaghava Aditya Renukunta 	srbcmd->flags = cpu_to_le32(SRB_DataIn);
1770c83b11e3SRaghava Aditya Renukunta 	srbcmd->timeout = cpu_to_le32(10);
1771c83b11e3SRaghava Aditya Renukunta 	srbcmd->retry_limit = 0;
1772c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb_size = cpu_to_le32(12);
1773c83b11e3SRaghava Aditya Renukunta 	srbcmd->count = cpu_to_le32(datasize);
1774c83b11e3SRaghava Aditya Renukunta 
1775c83b11e3SRaghava Aditya Renukunta 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1776c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS;
1777c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[1] = 2; /* extended reporting */
1778c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[8] = (u8)(datasize >> 8);
1779c83b11e3SRaghava Aditya Renukunta 	srbcmd->cdb[9] = (u8)(datasize);
1780c83b11e3SRaghava Aditya Renukunta 
1781c83b11e3SRaghava Aditya Renukunta 	sg64 = (struct sgmap64 *) &srbcmd->sg;
1782c83b11e3SRaghava Aditya Renukunta 	sg64->count = cpu_to_le32(1);
1783c83b11e3SRaghava Aditya Renukunta 	sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr));
1784c83b11e3SRaghava Aditya Renukunta 	sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr));
1785c83b11e3SRaghava Aditya Renukunta 	sg64->sg[0].count = cpu_to_le32(datasize);
1786c83b11e3SRaghava Aditya Renukunta 
1787c83b11e3SRaghava Aditya Renukunta 	rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize,
1788c83b11e3SRaghava Aditya Renukunta 			FsaNormal, 1, 1, NULL, NULL);
1789c83b11e3SRaghava Aditya Renukunta 
1790c83b11e3SRaghava Aditya Renukunta 	/* analyse data */
1791c83b11e3SRaghava Aditya Renukunta 	if (rcode >= 0 && phys_luns->resp_flag == 2) {
1792c83b11e3SRaghava Aditya Renukunta 		/* ok and extended reporting */
17936223a39fSRaghava Aditya Renukunta 		aac_update_hba_map(dev, phys_luns, rescan);
1794c83b11e3SRaghava Aditya Renukunta 	}
1795c83b11e3SRaghava Aditya Renukunta 
1796c83b11e3SRaghava Aditya Renukunta 	pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr);
1797c83b11e3SRaghava Aditya Renukunta err_out:
1798c83b11e3SRaghava Aditya Renukunta 	return rcode;
1799c83b11e3SRaghava Aditya Renukunta }
1800c83b11e3SRaghava Aditya Renukunta 
18011da177e4SLinus Torvalds int aac_get_adapter_info(struct aac_dev* dev)
18021da177e4SLinus Torvalds {
18031da177e4SLinus Torvalds 	struct fib* fibptr;
18041da177e4SLinus Torvalds 	int rcode;
1805c83b11e3SRaghava Aditya Renukunta 	u32 tmp, bus, target;
18067c00ffa3SMark Haverkamp  	struct aac_adapter_info *info;
180784971738SMark Haverkamp 	struct aac_bus_info *command;
180884971738SMark Haverkamp 	struct aac_bus_info_response *bus_info;
18097c00ffa3SMark Haverkamp  
1810bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
18111da177e4SLinus Torvalds 		return -ENOMEM;
18121da177e4SLinus Torvalds 
1813bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
18141da177e4SLinus Torvalds 	info = (struct aac_adapter_info *) fib_data(fibptr);
18157c00ffa3SMark Haverkamp  	memset(info,0,sizeof(*info));
18161da177e4SLinus Torvalds 
1817bfb35aa8SMark Haverkamp 	rcode = aac_fib_send(RequestAdapterInfo,
18181da177e4SLinus Torvalds 			 fibptr,
18197c00ffa3SMark Haverkamp  			 sizeof(*info),
18201da177e4SLinus Torvalds 			 FsaNormal,
18219203344cSMark Haverkamp 			 -1, 1, /* First `interrupt' command uses special wait */
18221da177e4SLinus Torvalds 			 NULL,
18231da177e4SLinus Torvalds 			 NULL);
18241da177e4SLinus Torvalds 
18257c00ffa3SMark Haverkamp  	if (rcode < 0) {
1826cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		/* FIB should be freed only after
1827cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		 * getting the response from the F/W */
1828cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		if (rcode != -ERESTARTSYS) {
1829bfb35aa8SMark Haverkamp 			aac_fib_complete(fibptr);
1830bfb35aa8SMark Haverkamp 			aac_fib_free(fibptr);
1831cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		}
18327c00ffa3SMark Haverkamp  		return rcode;
18337c00ffa3SMark Haverkamp  	}
18347c00ffa3SMark Haverkamp  	memcpy(&dev->adapter_info, info, sizeof(*info));
18357c00ffa3SMark Haverkamp  
1836c83b11e3SRaghava Aditya Renukunta 	dev->supplement_adapter_info.VirtDeviceBus = 0xffff;
18377c00ffa3SMark Haverkamp  	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
183806a43d17SSalyzyn, Mark 		struct aac_supplement_adapter_info * sinfo;
18397c00ffa3SMark Haverkamp  
1840bfb35aa8SMark Haverkamp 		aac_fib_init(fibptr);
18417c00ffa3SMark Haverkamp  
184206a43d17SSalyzyn, Mark 		sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
18437c00ffa3SMark Haverkamp  
184406a43d17SSalyzyn, Mark 		memset(sinfo,0,sizeof(*sinfo));
18457c00ffa3SMark Haverkamp  
1846bfb35aa8SMark Haverkamp 		rcode = aac_fib_send(RequestSupplementAdapterInfo,
18477c00ffa3SMark Haverkamp  				 fibptr,
184806a43d17SSalyzyn, Mark 				 sizeof(*sinfo),
18497c00ffa3SMark Haverkamp  				 FsaNormal,
18507c00ffa3SMark Haverkamp  				 1, 1,
18517c00ffa3SMark Haverkamp  				 NULL,
18527c00ffa3SMark Haverkamp  				 NULL);
18537c00ffa3SMark Haverkamp  
18547c00ffa3SMark Haverkamp  		if (rcode >= 0)
185506a43d17SSalyzyn, Mark 			memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
1856cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		if (rcode == -ERESTARTSYS) {
1857cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			fibptr = aac_fib_alloc(dev);
1858cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			if (!fibptr)
1859cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 				return -ENOMEM;
1860cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		}
1861cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
18627c00ffa3SMark Haverkamp  	}
18631da177e4SLinus Torvalds 
1864c83b11e3SRaghava Aditya Renukunta 	/* reset all previous mapped devices (i.e. for init. after IOP_RESET) */
1865c83b11e3SRaghava Aditya Renukunta 	for (bus = 0; bus < AAC_MAX_BUSES; bus++) {
186671a91ca4SRaghava Aditya Renukunta 		for (target = 0; target < AAC_MAX_TARGETS; target++) {
1867c83b11e3SRaghava Aditya Renukunta 			dev->hba_map[bus][target].devtype = 0;
186871a91ca4SRaghava Aditya Renukunta 			dev->hba_map[bus][target].qd_limit = 0;
186971a91ca4SRaghava Aditya Renukunta 		}
1870c83b11e3SRaghava Aditya Renukunta 	}
187184971738SMark Haverkamp 
187284971738SMark Haverkamp 	/*
187384971738SMark Haverkamp 	 * GetBusInfo
187484971738SMark Haverkamp 	 */
187584971738SMark Haverkamp 
1876bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
187784971738SMark Haverkamp 
187884971738SMark Haverkamp 	bus_info = (struct aac_bus_info_response *) fib_data(fibptr);
187984971738SMark Haverkamp 
188084971738SMark Haverkamp 	memset(bus_info, 0, sizeof(*bus_info));
188184971738SMark Haverkamp 
188284971738SMark Haverkamp 	command = (struct aac_bus_info *)bus_info;
188384971738SMark Haverkamp 
188484971738SMark Haverkamp 	command->Command = cpu_to_le32(VM_Ioctl);
188584971738SMark Haverkamp 	command->ObjType = cpu_to_le32(FT_DRIVE);
188684971738SMark Haverkamp 	command->MethodId = cpu_to_le32(1);
188784971738SMark Haverkamp 	command->CtlCmd = cpu_to_le32(GetBusInfo);
188884971738SMark Haverkamp 
1889bfb35aa8SMark Haverkamp 	rcode = aac_fib_send(ContainerCommand,
189084971738SMark Haverkamp 			 fibptr,
189184971738SMark Haverkamp 			 sizeof (*bus_info),
189284971738SMark Haverkamp 			 FsaNormal,
189384971738SMark Haverkamp 			 1, 1,
189484971738SMark Haverkamp 			 NULL, NULL);
189584971738SMark Haverkamp 
189694cf6ba1SSalyzyn, Mark 	/* reasoned default */
189794cf6ba1SSalyzyn, Mark 	dev->maximum_num_physicals = 16;
189884971738SMark Haverkamp 	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
189984971738SMark Haverkamp 		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
190084971738SMark Haverkamp 		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
190184971738SMark Haverkamp 	}
190284971738SMark Haverkamp 
1903c83b11e3SRaghava Aditya Renukunta 	if (!dev->sync_mode && dev->sa_firmware &&
1904c83b11e3SRaghava Aditya Renukunta 			dev->supplement_adapter_info.VirtDeviceBus != 0xffff) {
1905c83b11e3SRaghava Aditya Renukunta 		/* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
19066223a39fSRaghava Aditya Renukunta 		rcode = aac_report_phys_luns(dev, fibptr, AAC_INIT);
1907c83b11e3SRaghava Aditya Renukunta 	}
1908c83b11e3SRaghava Aditya Renukunta 
19098c867b25SMark Haverkamp 	if (!dev->in_reset) {
191024f02e1dSSalyzyn, Mark 		char buffer[16];
19111da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
19127c00ffa3SMark Haverkamp  		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
19131da177e4SLinus Torvalds 			dev->name,
19141da177e4SLinus Torvalds 			dev->id,
19151da177e4SLinus Torvalds 			tmp>>24,
19161da177e4SLinus Torvalds 			(tmp>>16)&0xff,
19171da177e4SLinus Torvalds 			tmp&0xff,
19187c00ffa3SMark Haverkamp  			le32_to_cpu(dev->adapter_info.kernelbuild),
19197c00ffa3SMark Haverkamp  			(int)sizeof(dev->supplement_adapter_info.BuildDate),
19207c00ffa3SMark Haverkamp  			dev->supplement_adapter_info.BuildDate);
19211da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.monitorrev);
19221da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
19231da177e4SLinus Torvalds 			dev->name, dev->id,
19241da177e4SLinus Torvalds 			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
19251da177e4SLinus Torvalds 			le32_to_cpu(dev->adapter_info.monitorbuild));
19261da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.biosrev);
19271da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
19281da177e4SLinus Torvalds 			dev->name, dev->id,
19291da177e4SLinus Torvalds 			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
19301da177e4SLinus Torvalds 			le32_to_cpu(dev->adapter_info.biosbuild));
193124f02e1dSSalyzyn, Mark 		buffer[0] = '\0';
1932ee959b00STony Jones 		if (aac_get_serial_number(
193324f02e1dSSalyzyn, Mark 		  shost_to_class(dev->scsi_host_ptr), buffer))
193424f02e1dSSalyzyn, Mark 			printk(KERN_INFO "%s%d: serial %s",
193524f02e1dSSalyzyn, Mark 			  dev->name, dev->id, buffer);
1936a45c863fSSalyzyn, Mark 		if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
1937a45c863fSSalyzyn, Mark 			printk(KERN_INFO "%s%d: TSID %.*s\n",
1938a45c863fSSalyzyn, Mark 			  dev->name, dev->id,
1939a45c863fSSalyzyn, Mark 			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
1940a45c863fSSalyzyn, Mark 			  dev->supplement_adapter_info.VpdInfo.Tsid);
1941a45c863fSSalyzyn, Mark 		}
19422f7ecc55SSalyzyn, Mark 		if (!aac_check_reset || ((aac_check_reset == 1) &&
194329c97684SSalyzyn, Mark 		  (dev->supplement_adapter_info.SupportedOptions2 &
1944a3940da5SSalyzyn, Mark 		  AAC_OPTION_IGNORE_RESET))) {
194529c97684SSalyzyn, Mark 			printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
194629c97684SSalyzyn, Mark 			  dev->name, dev->id);
194729c97684SSalyzyn, Mark 		}
19488c867b25SMark Haverkamp 	}
19491da177e4SLinus Torvalds 
195095e852e1SSalyzyn, Mark 	dev->cache_protected = 0;
1951cb1042f2SSalyzyn, Mark 	dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
1952cb1042f2SSalyzyn, Mark 		AAC_FEATURE_JBOD) != 0);
19531da177e4SLinus Torvalds 	dev->nondasd_support = 0;
19541da177e4SLinus Torvalds 	dev->raid_scsi_mode = 0;
195595e852e1SSalyzyn, Mark 	if(dev->adapter_info.options & AAC_OPT_NONDASD)
19561da177e4SLinus Torvalds 		dev->nondasd_support = 1;
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 	/*
19591da177e4SLinus Torvalds 	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
19601da177e4SLinus Torvalds 	 * in RAID/SCSI mode, set the flag. For now if in this mode we will
19611da177e4SLinus Torvalds 	 * force nondasd support on. If we decide to allow the non-dasd flag
19621da177e4SLinus Torvalds 	 * additional changes changes will have to be made to support
19631da177e4SLinus Torvalds 	 * RAID/SCSI.  the function aac_scsi_cmd in this module will have to be
19641da177e4SLinus Torvalds 	 * changed to support the new dev->raid_scsi_mode flag instead of
19651da177e4SLinus Torvalds 	 * leaching off of the dev->nondasd_support flag. Also in linit.c the
19661da177e4SLinus Torvalds 	 * function aac_detect will have to be modified where it sets up the
19671da177e4SLinus Torvalds 	 * max number of channels based on the aac->nondasd_support flag only.
19681da177e4SLinus Torvalds 	 */
19691da177e4SLinus Torvalds 	if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
19701da177e4SLinus Torvalds 	    (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
19711da177e4SLinus Torvalds 		dev->nondasd_support = 1;
19721da177e4SLinus Torvalds 		dev->raid_scsi_mode = 1;
19731da177e4SLinus Torvalds 	}
19741da177e4SLinus Torvalds 	if (dev->raid_scsi_mode != 0)
19751da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
19761da177e4SLinus Torvalds 				dev->name, dev->id);
19771da177e4SLinus Torvalds 
197895e852e1SSalyzyn, Mark 	if (nondasd != -1)
19791da177e4SLinus Torvalds 		dev->nondasd_support = (nondasd!=0);
19802f7ecc55SSalyzyn, Mark 	if (dev->nondasd_support && !dev->in_reset)
19811da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
19821da177e4SLinus Torvalds 
1983e930438cSYang Hongyang 	if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32))
1984d8e96507SLeubner, Achim 		dev->needs_dac = 1;
19851da177e4SLinus Torvalds 	dev->dac_support = 0;
1986d8e96507SLeubner, Achim 	if ((sizeof(dma_addr_t) > 4) && dev->needs_dac &&
1987d8e96507SLeubner, Achim 	    (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) {
19882f7ecc55SSalyzyn, Mark 		if (!dev->in_reset)
19892f7ecc55SSalyzyn, Mark 			printk(KERN_INFO "%s%d: 64bit support enabled.\n",
19902f7ecc55SSalyzyn, Mark 				dev->name, dev->id);
19911da177e4SLinus Torvalds 		dev->dac_support = 1;
19921da177e4SLinus Torvalds 	}
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	if(dacmode != -1) {
19951da177e4SLinus Torvalds 		dev->dac_support = (dacmode!=0);
19961da177e4SLinus Torvalds 	}
1997d8e96507SLeubner, Achim 
1998d8e96507SLeubner, Achim 	/* avoid problems with AAC_QUIRK_SCSI_32 controllers */
1999d8e96507SLeubner, Achim 	if (dev->dac_support &&	(aac_get_driver_ident(dev->cardtype)->quirks
2000d8e96507SLeubner, Achim 		& AAC_QUIRK_SCSI_32)) {
2001d8e96507SLeubner, Achim 		dev->nondasd_support = 0;
2002d8e96507SLeubner, Achim 		dev->jbod = 0;
2003d8e96507SLeubner, Achim 		expose_physicals = 0;
2004d8e96507SLeubner, Achim 	}
2005d8e96507SLeubner, Achim 
20061da177e4SLinus Torvalds 	if(dev->dac_support != 0) {
20076a35528aSYang Hongyang 		if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) &&
20086a35528aSYang Hongyang 			!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
20092f7ecc55SSalyzyn, Mark 			if (!dev->in_reset)
20101da177e4SLinus Torvalds 				printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
20111da177e4SLinus Torvalds 					dev->name, dev->id);
2012284901a9SYang Hongyang 		} else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) &&
2013284901a9SYang Hongyang 			!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) {
20141da177e4SLinus Torvalds 			printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
20151da177e4SLinus Torvalds 				dev->name, dev->id);
20161da177e4SLinus Torvalds 			dev->dac_support = 0;
20171da177e4SLinus Torvalds 		} else {
20181da177e4SLinus Torvalds 			printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
20191da177e4SLinus Torvalds 				dev->name, dev->id);
20201da177e4SLinus Torvalds 			rcode = -ENOMEM;
20211da177e4SLinus Torvalds 		}
20221da177e4SLinus Torvalds 	}
20237c00ffa3SMark Haverkamp  	/*
2024e8f32de5SMark Haverkamp 	 * Deal with configuring for the individualized limits of each packet
2025e8f32de5SMark Haverkamp 	 * interface.
20267c00ffa3SMark Haverkamp  	 */
2027e8f32de5SMark Haverkamp 	dev->a_ops.adapter_scsi = (dev->dac_support)
202894cf6ba1SSalyzyn, Mark 	  ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
202994cf6ba1SSalyzyn, Mark 				? aac_scsi_32_64
203094cf6ba1SSalyzyn, Mark 				: aac_scsi_64)
2031e8f32de5SMark Haverkamp 				: aac_scsi_32;
2032e8f32de5SMark Haverkamp 	if (dev->raw_io_interface) {
2033e8f32de5SMark Haverkamp 		dev->a_ops.adapter_bounds = (dev->raw_io_64)
2034e8f32de5SMark Haverkamp 					? aac_bounds_64
2035e8f32de5SMark Haverkamp 					: aac_bounds_32;
2036e8f32de5SMark Haverkamp 		dev->a_ops.adapter_read = aac_read_raw_io;
2037e8f32de5SMark Haverkamp 		dev->a_ops.adapter_write = aac_write_raw_io;
2038e8f32de5SMark Haverkamp 	} else {
2039e8f32de5SMark Haverkamp 		dev->a_ops.adapter_bounds = aac_bounds_32;
20407c00ffa3SMark Haverkamp  		dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
20417c00ffa3SMark Haverkamp  			sizeof(struct aac_fibhdr) -
204263a70eeaSMark Haverkamp 			sizeof(struct aac_write) + sizeof(struct sgentry)) /
204363a70eeaSMark Haverkamp 				sizeof(struct sgentry);
20447c00ffa3SMark Haverkamp  		if (dev->dac_support) {
2045e8f32de5SMark Haverkamp 			dev->a_ops.adapter_read = aac_read_block64;
2046e8f32de5SMark Haverkamp 			dev->a_ops.adapter_write = aac_write_block64;
20477c00ffa3SMark Haverkamp  			/*
20487c00ffa3SMark Haverkamp  			 * 38 scatter gather elements
20497c00ffa3SMark Haverkamp  			 */
20507c00ffa3SMark Haverkamp  			dev->scsi_host_ptr->sg_tablesize =
20517c00ffa3SMark Haverkamp  				(dev->max_fib_size -
20527c00ffa3SMark Haverkamp  				sizeof(struct aac_fibhdr) -
20537c00ffa3SMark Haverkamp  				sizeof(struct aac_write64) +
205463a70eeaSMark Haverkamp 				sizeof(struct sgentry64)) /
205563a70eeaSMark Haverkamp 					sizeof(struct sgentry64);
2056e8f32de5SMark Haverkamp 		} else {
2057e8f32de5SMark Haverkamp 			dev->a_ops.adapter_read = aac_read_block;
2058e8f32de5SMark Haverkamp 			dev->a_ops.adapter_write = aac_write_block;
20597c00ffa3SMark Haverkamp  		}
20607c00ffa3SMark Haverkamp  		dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
20617c00ffa3SMark Haverkamp  		if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
20627c00ffa3SMark Haverkamp  			/*
20637c00ffa3SMark Haverkamp  			 * Worst case size that could cause sg overflow when
20647c00ffa3SMark Haverkamp  			 * we break up SG elements that are larger than 64KB.
20657c00ffa3SMark Haverkamp  			 * Would be nice if we could tell the SCSI layer what
20667c00ffa3SMark Haverkamp  			 * the maximum SG element size can be. Worst case is
20677c00ffa3SMark Haverkamp  			 * (sg_tablesize-1) 4KB elements with one 64KB
20687c00ffa3SMark Haverkamp  			 * element.
20697c00ffa3SMark Haverkamp  			 *	32bit -> 468 or 238KB	64bit -> 424 or 212KB
20707c00ffa3SMark Haverkamp  			 */
20717c00ffa3SMark Haverkamp  			dev->scsi_host_ptr->max_sectors =
20727c00ffa3SMark Haverkamp  			  (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
20737c00ffa3SMark Haverkamp  		}
20740e68c003SMark Haverkamp 	}
2075ab5d129fSRaghava Aditya Renukunta 	if (!dev->sync_mode && dev->sa_firmware &&
2076ab5d129fSRaghava Aditya Renukunta 		dev->scsi_host_ptr->sg_tablesize > HBA_MAX_SG_SEPARATE)
2077ab5d129fSRaghava Aditya Renukunta 		dev->scsi_host_ptr->sg_tablesize = dev->sg_tablesize =
2078ab5d129fSRaghava Aditya Renukunta 			HBA_MAX_SG_SEPARATE;
2079ab5d129fSRaghava Aditya Renukunta 
2080cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
2081cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (rcode != -ERESTARTSYS) {
2082bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
2083bfb35aa8SMark Haverkamp 		aac_fib_free(fibptr);
2084cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	}
20851da177e4SLinus Torvalds 
20861da177e4SLinus Torvalds 	return rcode;
20871da177e4SLinus Torvalds }
20881da177e4SLinus Torvalds 
20891da177e4SLinus Torvalds 
2090e53cb35aSMark Haverkamp static void io_callback(void *context, struct fib * fibptr)
20911da177e4SLinus Torvalds {
20921da177e4SLinus Torvalds 	struct aac_dev *dev;
20931da177e4SLinus Torvalds 	struct aac_read_reply *readreply;
20941da177e4SLinus Torvalds 	struct scsi_cmnd *scsicmd;
20951da177e4SLinus Torvalds 	u32 cid;
20961da177e4SLinus Torvalds 
20971da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
20981da177e4SLinus Torvalds 
209903d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
210003d44337SMark Haverkamp 		return;
210103d44337SMark Haverkamp 
21021a655040SSalyzyn, Mark 	dev = fibptr->dev;
2103e5718774SMark Haverkamp 	cid = scmd_id(scsicmd);
21041da177e4SLinus Torvalds 
21057a8cf29dSMark Haverkamp 	if (nblank(dprintk(x))) {
21067a8cf29dSMark Haverkamp 		u64 lba;
21077a8cf29dSMark Haverkamp 		switch (scsicmd->cmnd[0]) {
21087a8cf29dSMark Haverkamp 		case WRITE_6:
21097a8cf29dSMark Haverkamp 		case READ_6:
21107a8cf29dSMark Haverkamp 			lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
21117a8cf29dSMark Haverkamp 			    (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
21127a8cf29dSMark Haverkamp 			break;
21137a8cf29dSMark Haverkamp 		case WRITE_16:
21147a8cf29dSMark Haverkamp 		case READ_16:
21157a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 56) |
21167a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[3] << 48) |
21177a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[4] << 40) |
21187a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[5] << 32) |
21197a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[6] << 24) |
21207a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[7] << 16) |
21217a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
21227a8cf29dSMark Haverkamp 			break;
21237a8cf29dSMark Haverkamp 		case WRITE_12:
21247a8cf29dSMark Haverkamp 		case READ_12:
21257a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 24) |
21267a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[3] << 16) |
21277a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
21287a8cf29dSMark Haverkamp 			break;
21297a8cf29dSMark Haverkamp 		default:
21307a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 24) |
21317a8cf29dSMark Haverkamp 			       (scsicmd->cmnd[3] << 16) |
21327a8cf29dSMark Haverkamp 			       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
21337a8cf29dSMark Haverkamp 			break;
21347a8cf29dSMark Haverkamp 		}
21357a8cf29dSMark Haverkamp 		printk(KERN_DEBUG
21367a8cf29dSMark Haverkamp 		  "io_callback[cpu %d]: lba = %llu, t = %ld.\n",
21377a8cf29dSMark Haverkamp 		  smp_processor_id(), (unsigned long long)lba, jiffies);
21387a8cf29dSMark Haverkamp 	}
21391da177e4SLinus Torvalds 
2140125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
21411da177e4SLinus Torvalds 
2142727eead6SFUJITA Tomonori 	scsi_dma_unmap(scsicmd);
2143727eead6SFUJITA Tomonori 
21441da177e4SLinus Torvalds 	readreply = (struct aac_read_reply *)fib_data(fibptr);
2145655d722cSMark Salyzyn 	switch (le32_to_cpu(readreply->status)) {
2146655d722cSMark Salyzyn 	case ST_OK:
2147655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2148655d722cSMark Salyzyn 			SAM_STAT_GOOD;
2149655d722cSMark Salyzyn 		dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
2150655d722cSMark Salyzyn 		break;
2151655d722cSMark Salyzyn 	case ST_NOT_READY:
2152655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2153655d722cSMark Salyzyn 			SAM_STAT_CHECK_CONDITION;
2154655d722cSMark Salyzyn 		set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
2155655d722cSMark Salyzyn 		  SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
2156655d722cSMark Salyzyn 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2157655d722cSMark Salyzyn 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2158655d722cSMark Salyzyn 			     SCSI_SENSE_BUFFERSIZE));
2159655d722cSMark Salyzyn 		break;
2160f956a669SRaghava Aditya Renukunta 	case ST_MEDERR:
2161f956a669SRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2162f956a669SRaghava Aditya Renukunta 			SAM_STAT_CHECK_CONDITION;
2163f956a669SRaghava Aditya Renukunta 		set_sense(&dev->fsa_dev[cid].sense_data, MEDIUM_ERROR,
2164f956a669SRaghava Aditya Renukunta 		  SENCODE_UNRECOVERED_READ_ERROR, ASENCODE_NO_SENSE, 0, 0);
2165f956a669SRaghava Aditya Renukunta 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2166f956a669SRaghava Aditya Renukunta 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2167f956a669SRaghava Aditya Renukunta 			     SCSI_SENSE_BUFFERSIZE));
2168f956a669SRaghava Aditya Renukunta 		break;
2169655d722cSMark Salyzyn 	default:
21707c00ffa3SMark Haverkamp  #ifdef AAC_DETAILED_STATUS_INFO
2171e53cb35aSMark Haverkamp 		printk(KERN_WARNING "io_callback: io failed, status = %d\n",
21721da177e4SLinus Torvalds 		  le32_to_cpu(readreply->status));
21737c00ffa3SMark Haverkamp  #endif
2174655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2175655d722cSMark Salyzyn 			SAM_STAT_CHECK_CONDITION;
21768e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
21778e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
21788e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
21791da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
21803ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
21813ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
2182655d722cSMark Salyzyn 		break;
21831da177e4SLinus Torvalds 	}
2184bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
21851da177e4SLinus Torvalds 
21868e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
21871da177e4SLinus Torvalds }
21881da177e4SLinus Torvalds 
21899e7c349cSMark Haverkamp static int aac_read(struct scsi_cmnd * scsicmd)
21901da177e4SLinus Torvalds {
21917a8cf29dSMark Haverkamp 	u64 lba;
21921da177e4SLinus Torvalds 	u32 count;
21931da177e4SLinus Torvalds 	int status;
21941da177e4SLinus Torvalds 	struct aac_dev *dev;
21951da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
2196da3cc679SRajashekhara, Mahesh 	int cid;
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
21991da177e4SLinus Torvalds 	/*
22001da177e4SLinus Torvalds 	 *	Get block address and transfer length
22011da177e4SLinus Torvalds 	 */
22027a8cf29dSMark Haverkamp 	switch (scsicmd->cmnd[0]) {
22037a8cf29dSMark Haverkamp 	case READ_6:
22049e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
22051da177e4SLinus Torvalds 
22067a8cf29dSMark Haverkamp 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
22077a8cf29dSMark Haverkamp 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
22081da177e4SLinus Torvalds 		count = scsicmd->cmnd[4];
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds 		if (count == 0)
22111da177e4SLinus Torvalds 			count = 256;
22127a8cf29dSMark Haverkamp 		break;
22137a8cf29dSMark Haverkamp 	case READ_16:
22149e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
22157a8cf29dSMark Haverkamp 
22167a8cf29dSMark Haverkamp 		lba =	((u64)scsicmd->cmnd[2] << 56) |
22177a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[3] << 48) |
22187a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[4] << 40) |
22197a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[5] << 32) |
22207a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[6] << 24) |
22217a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
22227a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
22237a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[10] << 24) |
22247a8cf29dSMark Haverkamp 			(scsicmd->cmnd[11] << 16) |
22257a8cf29dSMark Haverkamp 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
22267a8cf29dSMark Haverkamp 		break;
22277a8cf29dSMark Haverkamp 	case READ_12:
22289e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
22297a8cf29dSMark Haverkamp 
22307a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) |
22317a8cf29dSMark Haverkamp 			(scsicmd->cmnd[3] << 16) |
22327a8cf29dSMark Haverkamp 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
22337a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[6] << 24) |
22347a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
22357a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
22367a8cf29dSMark Haverkamp 		break;
22377a8cf29dSMark Haverkamp 	default:
22389e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
22391da177e4SLinus Torvalds 
22407a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) |
22417a8cf29dSMark Haverkamp 			(scsicmd->cmnd[3] << 16) |
22427a8cf29dSMark Haverkamp 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
22431da177e4SLinus Torvalds 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
22447a8cf29dSMark Haverkamp 		break;
22451da177e4SLinus Torvalds 	}
2246da3cc679SRajashekhara, Mahesh 
2247da3cc679SRajashekhara, Mahesh 	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
2248da3cc679SRajashekhara, Mahesh 		cid = scmd_id(scsicmd);
2249da3cc679SRajashekhara, Mahesh 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
2250da3cc679SRajashekhara, Mahesh 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2251da3cc679SRajashekhara, Mahesh 			SAM_STAT_CHECK_CONDITION;
2252da3cc679SRajashekhara, Mahesh 		set_sense(&dev->fsa_dev[cid].sense_data,
2253da3cc679SRajashekhara, Mahesh 			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
2254da3cc679SRajashekhara, Mahesh 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
2255da3cc679SRajashekhara, Mahesh 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2256da3cc679SRajashekhara, Mahesh 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2257da3cc679SRajashekhara, Mahesh 			     SCSI_SENSE_BUFFERSIZE));
2258da3cc679SRajashekhara, Mahesh 		scsicmd->scsi_done(scsicmd);
2259da3cc679SRajashekhara, Mahesh 		return 1;
2260da3cc679SRajashekhara, Mahesh 	}
2261da3cc679SRajashekhara, Mahesh 
22627a8cf29dSMark Haverkamp 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
22637c00ffa3SMark Haverkamp  	  smp_processor_id(), (unsigned long long)lba, jiffies));
2264e8f32de5SMark Haverkamp 	if (aac_adapter_bounds(dev,scsicmd,lba))
22657a8cf29dSMark Haverkamp 		return 0;
22661da177e4SLinus Torvalds 	/*
22671da177e4SLinus Torvalds 	 *	Alocate and initialize a Fib
22681da177e4SLinus Torvalds 	 */
22696bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
22701da177e4SLinus Torvalds 
2271e8f32de5SMark Haverkamp 	status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
22721da177e4SLinus Torvalds 
22731da177e4SLinus Torvalds 	/*
22741da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
22751da177e4SLinus Torvalds 	 */
227677d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
227777d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
22781da177e4SLinus Torvalds 		return 0;
227977d644d4SMark Haverkamp 	}
22801da177e4SLinus Torvalds 
2281bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
22821da177e4SLinus Torvalds 	/*
22831da177e4SLinus Torvalds 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
22841da177e4SLinus Torvalds 	 */
22851da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
22868e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
2287bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2288bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
22891da177e4SLinus Torvalds 	return 0;
22901da177e4SLinus Torvalds }
22911da177e4SLinus Torvalds 
22929e7c349cSMark Haverkamp static int aac_write(struct scsi_cmnd * scsicmd)
22931da177e4SLinus Torvalds {
22947a8cf29dSMark Haverkamp 	u64 lba;
22951da177e4SLinus Torvalds 	u32 count;
22969d399cc7SSalyzyn, Mark 	int fua;
22971da177e4SLinus Torvalds 	int status;
22981da177e4SLinus Torvalds 	struct aac_dev *dev;
22991da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
2300da3cc679SRajashekhara, Mahesh 	int cid;
23011da177e4SLinus Torvalds 
23021da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
23031da177e4SLinus Torvalds 	/*
23041da177e4SLinus Torvalds 	 *	Get block address and transfer length
23051da177e4SLinus Torvalds 	 */
23061da177e4SLinus Torvalds 	if (scsicmd->cmnd[0] == WRITE_6)	/* 6 byte command */
23071da177e4SLinus Torvalds 	{
23081da177e4SLinus Torvalds 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
23091da177e4SLinus Torvalds 		count = scsicmd->cmnd[4];
23101da177e4SLinus Torvalds 		if (count == 0)
23111da177e4SLinus Torvalds 			count = 256;
23129d399cc7SSalyzyn, Mark 		fua = 0;
23137a8cf29dSMark Haverkamp 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
23149e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
23157a8cf29dSMark Haverkamp 
23167a8cf29dSMark Haverkamp 		lba =	((u64)scsicmd->cmnd[2] << 56) |
23177a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[3] << 48) |
23187a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[4] << 40) |
23197a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[5] << 32) |
23207a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[6] << 24) |
23217a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
23227a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
23237a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
23247a8cf29dSMark Haverkamp 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
23259d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
23267a8cf29dSMark Haverkamp 	} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
23279e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
23287a8cf29dSMark Haverkamp 
23297a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
23307a8cf29dSMark Haverkamp 		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
23317a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
23327a8cf29dSMark Haverkamp 		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
23339d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
23341da177e4SLinus Torvalds 	} else {
23359e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
23367a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
23371da177e4SLinus Torvalds 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
23389d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
23391da177e4SLinus Torvalds 	}
2340da3cc679SRajashekhara, Mahesh 
2341da3cc679SRajashekhara, Mahesh 	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
2342da3cc679SRajashekhara, Mahesh 		cid = scmd_id(scsicmd);
2343da3cc679SRajashekhara, Mahesh 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
2344da3cc679SRajashekhara, Mahesh 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2345da3cc679SRajashekhara, Mahesh 			SAM_STAT_CHECK_CONDITION;
2346da3cc679SRajashekhara, Mahesh 		set_sense(&dev->fsa_dev[cid].sense_data,
2347da3cc679SRajashekhara, Mahesh 			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
2348da3cc679SRajashekhara, Mahesh 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
2349da3cc679SRajashekhara, Mahesh 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2350da3cc679SRajashekhara, Mahesh 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2351da3cc679SRajashekhara, Mahesh 			     SCSI_SENSE_BUFFERSIZE));
2352da3cc679SRajashekhara, Mahesh 		scsicmd->scsi_done(scsicmd);
2353da3cc679SRajashekhara, Mahesh 		return 1;
2354da3cc679SRajashekhara, Mahesh 	}
2355da3cc679SRajashekhara, Mahesh 
23567a8cf29dSMark Haverkamp 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
23571da177e4SLinus Torvalds 	  smp_processor_id(), (unsigned long long)lba, jiffies));
2358e8f32de5SMark Haverkamp 	if (aac_adapter_bounds(dev,scsicmd,lba))
23597a8cf29dSMark Haverkamp 		return 0;
23601da177e4SLinus Torvalds 	/*
23611da177e4SLinus Torvalds 	 *	Allocate and initialize a Fib then setup a BlockWrite command
23621da177e4SLinus Torvalds 	 */
23636bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
23641da177e4SLinus Torvalds 
23659d399cc7SSalyzyn, Mark 	status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
23661da177e4SLinus Torvalds 
23671da177e4SLinus Torvalds 	/*
23681da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
23691da177e4SLinus Torvalds 	 */
237077d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
237177d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
23721da177e4SLinus Torvalds 		return 0;
23731da177e4SLinus Torvalds 	}
23741da177e4SLinus Torvalds 
2375bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
23761da177e4SLinus Torvalds 	/*
23771da177e4SLinus Torvalds 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
23781da177e4SLinus Torvalds 	 */
23791da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
23808e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
23811da177e4SLinus Torvalds 
2382bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2383bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
23841da177e4SLinus Torvalds 	return 0;
23851da177e4SLinus Torvalds }
23861da177e4SLinus Torvalds 
23871da177e4SLinus Torvalds static void synchronize_callback(void *context, struct fib *fibptr)
23881da177e4SLinus Torvalds {
23891da177e4SLinus Torvalds 	struct aac_synchronize_reply *synchronizereply;
23901da177e4SLinus Torvalds 	struct scsi_cmnd *cmd;
23911da177e4SLinus Torvalds 
23921da177e4SLinus Torvalds 	cmd = context;
23931da177e4SLinus Torvalds 
239403d44337SMark Haverkamp 	if (!aac_valid_context(cmd, fibptr))
239503d44337SMark Haverkamp 		return;
239603d44337SMark Haverkamp 
23971da177e4SLinus Torvalds 	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
23981da177e4SLinus Torvalds 				smp_processor_id(), jiffies));
23991da177e4SLinus Torvalds 	BUG_ON(fibptr == NULL);
24001da177e4SLinus Torvalds 
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds 	synchronizereply = fib_data(fibptr);
24031da177e4SLinus Torvalds 	if (le32_to_cpu(synchronizereply->status) == CT_OK)
24041da177e4SLinus Torvalds 		cmd->result = DID_OK << 16 |
24051da177e4SLinus Torvalds 			COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
24061da177e4SLinus Torvalds 	else {
24071da177e4SLinus Torvalds 		struct scsi_device *sdev = cmd->device;
24081a655040SSalyzyn, Mark 		struct aac_dev *dev = fibptr->dev;
2409e5718774SMark Haverkamp 		u32 cid = sdev_id(sdev);
24101da177e4SLinus Torvalds 		printk(KERN_WARNING
24111da177e4SLinus Torvalds 		     "synchronize_callback: synchronize failed, status = %d\n",
24121da177e4SLinus Torvalds 		     le32_to_cpu(synchronizereply->status));
24131da177e4SLinus Torvalds 		cmd->result = DID_OK << 16 |
24141da177e4SLinus Torvalds 			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
24158e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
24168e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
24178e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
24181da177e4SLinus Torvalds 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
2419b80ca4f7SFUJITA Tomonori 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
2420b80ca4f7SFUJITA Tomonori 			     SCSI_SENSE_BUFFERSIZE));
24211da177e4SLinus Torvalds 	}
24221da177e4SLinus Torvalds 
2423bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
2424bfb35aa8SMark Haverkamp 	aac_fib_free(fibptr);
24258e0c5ebdSMark Haverkamp 	cmd->scsi_done(cmd);
24261da177e4SLinus Torvalds }
24271da177e4SLinus Torvalds 
24289e7c349cSMark Haverkamp static int aac_synchronize(struct scsi_cmnd *scsicmd)
24291da177e4SLinus Torvalds {
24301da177e4SLinus Torvalds 	int status;
24311da177e4SLinus Torvalds 	struct fib *cmd_fibcontext;
24321da177e4SLinus Torvalds 	struct aac_synchronize *synchronizecmd;
24331da177e4SLinus Torvalds 	struct scsi_cmnd *cmd;
24341da177e4SLinus Torvalds 	struct scsi_device *sdev = scsicmd->device;
24351da177e4SLinus Torvalds 	int active = 0;
243690ee3466SMark Haverkamp 	struct aac_dev *aac;
2437b90f90d2SSalyzyn, Mark 	u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) |
2438b90f90d2SSalyzyn, Mark 		(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
2439b90f90d2SSalyzyn, Mark 	u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
24401da177e4SLinus Torvalds 	unsigned long flags;
24411da177e4SLinus Torvalds 
24421da177e4SLinus Torvalds 	/*
244377d644d4SMark Haverkamp 	 * Wait for all outstanding queued commands to complete to this
244477d644d4SMark Haverkamp 	 * specific target (block).
24451da177e4SLinus Torvalds 	 */
24461da177e4SLinus Torvalds 	spin_lock_irqsave(&sdev->list_lock, flags);
24471da177e4SLinus Torvalds 	list_for_each_entry(cmd, &sdev->cmd_list, list)
2448b90f90d2SSalyzyn, Mark 		if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
2449b90f90d2SSalyzyn, Mark 			u64 cmnd_lba;
2450b90f90d2SSalyzyn, Mark 			u32 cmnd_count;
2451b90f90d2SSalyzyn, Mark 
2452b90f90d2SSalyzyn, Mark 			if (cmd->cmnd[0] == WRITE_6) {
2453b90f90d2SSalyzyn, Mark 				cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) |
2454b90f90d2SSalyzyn, Mark 					(cmd->cmnd[2] << 8) |
2455b90f90d2SSalyzyn, Mark 					cmd->cmnd[3];
2456b90f90d2SSalyzyn, Mark 				cmnd_count = cmd->cmnd[4];
2457b90f90d2SSalyzyn, Mark 				if (cmnd_count == 0)
2458b90f90d2SSalyzyn, Mark 					cmnd_count = 256;
2459b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_16) {
2460b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 56) |
2461b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[3] << 48) |
2462b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[4] << 40) |
2463b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[5] << 32) |
2464b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[6] << 24) |
2465b90f90d2SSalyzyn, Mark 					(cmd->cmnd[7] << 16) |
2466b90f90d2SSalyzyn, Mark 					(cmd->cmnd[8] << 8) |
2467b90f90d2SSalyzyn, Mark 					cmd->cmnd[9];
2468b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[10] << 24) |
2469b90f90d2SSalyzyn, Mark 					(cmd->cmnd[11] << 16) |
2470b90f90d2SSalyzyn, Mark 					(cmd->cmnd[12] << 8) |
2471b90f90d2SSalyzyn, Mark 					cmd->cmnd[13];
2472b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_12) {
2473b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
2474b90f90d2SSalyzyn, Mark 					(cmd->cmnd[3] << 16) |
2475b90f90d2SSalyzyn, Mark 					(cmd->cmnd[4] << 8) |
2476b90f90d2SSalyzyn, Mark 					cmd->cmnd[5];
2477b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[6] << 24) |
2478b90f90d2SSalyzyn, Mark 					(cmd->cmnd[7] << 16) |
2479b90f90d2SSalyzyn, Mark 					(cmd->cmnd[8] << 8) |
2480b90f90d2SSalyzyn, Mark 					cmd->cmnd[9];
2481b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_10) {
2482b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
2483b90f90d2SSalyzyn, Mark 					(cmd->cmnd[3] << 16) |
2484b90f90d2SSalyzyn, Mark 					(cmd->cmnd[4] << 8) |
2485b90f90d2SSalyzyn, Mark 					cmd->cmnd[5];
2486b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[7] << 8) |
2487b90f90d2SSalyzyn, Mark 					cmd->cmnd[8];
2488b90f90d2SSalyzyn, Mark 			} else
2489b90f90d2SSalyzyn, Mark 				continue;
2490b90f90d2SSalyzyn, Mark 			if (((cmnd_lba + cmnd_count) < lba) ||
2491b90f90d2SSalyzyn, Mark 			  (count && ((lba + count) < cmnd_lba)))
2492b90f90d2SSalyzyn, Mark 				continue;
24931da177e4SLinus Torvalds 			++active;
24941da177e4SLinus Torvalds 			break;
24951da177e4SLinus Torvalds 		}
24961da177e4SLinus Torvalds 
24971da177e4SLinus Torvalds 	spin_unlock_irqrestore(&sdev->list_lock, flags);
24981da177e4SLinus Torvalds 
24991da177e4SLinus Torvalds 	/*
25001da177e4SLinus Torvalds 	 *	Yield the processor (requeue for later)
25011da177e4SLinus Torvalds 	 */
25021da177e4SLinus Torvalds 	if (active)
25031da177e4SLinus Torvalds 		return SCSI_MLQUEUE_DEVICE_BUSY;
25041da177e4SLinus Torvalds 
2505f858317dSSalyzyn, Mark 	aac = (struct aac_dev *)sdev->host->hostdata;
25068c867b25SMark Haverkamp 	if (aac->in_reset)
25078c867b25SMark Haverkamp 		return SCSI_MLQUEUE_HOST_BUSY;
25088c867b25SMark Haverkamp 
25091da177e4SLinus Torvalds 	/*
25107c00ffa3SMark Haverkamp  	 *	Allocate and initialize a Fib
25111da177e4SLinus Torvalds 	 */
251290ee3466SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(aac)))
25131da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
25141da177e4SLinus Torvalds 
2515bfb35aa8SMark Haverkamp 	aac_fib_init(cmd_fibcontext);
25161da177e4SLinus Torvalds 
25171da177e4SLinus Torvalds 	synchronizecmd = fib_data(cmd_fibcontext);
25181da177e4SLinus Torvalds 	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
25191da177e4SLinus Torvalds 	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
25209e7c349cSMark Haverkamp 	synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
25211da177e4SLinus Torvalds 	synchronizecmd->count =
25221da177e4SLinus Torvalds 	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
25231da177e4SLinus Torvalds 
25241da177e4SLinus Torvalds 	/*
25251da177e4SLinus Torvalds 	 *	Now send the Fib to the adapter
25261da177e4SLinus Torvalds 	 */
2527bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
25281da177e4SLinus Torvalds 		  cmd_fibcontext,
25291da177e4SLinus Torvalds 		  sizeof(struct aac_synchronize),
25301da177e4SLinus Torvalds 		  FsaNormal,
25311da177e4SLinus Torvalds 		  0, 1,
25321da177e4SLinus Torvalds 		  (fib_callback)synchronize_callback,
25331da177e4SLinus Torvalds 		  (void *)scsicmd);
25341da177e4SLinus Torvalds 
25351da177e4SLinus Torvalds 	/*
25361da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
25371da177e4SLinus Torvalds 	 */
253877d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
253977d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
25401da177e4SLinus Torvalds 		return 0;
254177d644d4SMark Haverkamp 	}
25421da177e4SLinus Torvalds 
25431da177e4SLinus Torvalds 	printk(KERN_WARNING
2544bfb35aa8SMark Haverkamp 		"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
2545bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2546bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
25471da177e4SLinus Torvalds 	return SCSI_MLQUEUE_HOST_BUSY;
25481da177e4SLinus Torvalds }
25491da177e4SLinus Torvalds 
2550655d722cSMark Salyzyn static void aac_start_stop_callback(void *context, struct fib *fibptr)
2551655d722cSMark Salyzyn {
2552655d722cSMark Salyzyn 	struct scsi_cmnd *scsicmd = context;
2553655d722cSMark Salyzyn 
2554655d722cSMark Salyzyn 	if (!aac_valid_context(scsicmd, fibptr))
2555655d722cSMark Salyzyn 		return;
2556655d722cSMark Salyzyn 
2557655d722cSMark Salyzyn 	BUG_ON(fibptr == NULL);
2558655d722cSMark Salyzyn 
2559655d722cSMark Salyzyn 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
2560655d722cSMark Salyzyn 
2561655d722cSMark Salyzyn 	aac_fib_complete(fibptr);
2562655d722cSMark Salyzyn 	aac_fib_free(fibptr);
2563655d722cSMark Salyzyn 	scsicmd->scsi_done(scsicmd);
2564655d722cSMark Salyzyn }
2565655d722cSMark Salyzyn 
2566655d722cSMark Salyzyn static int aac_start_stop(struct scsi_cmnd *scsicmd)
2567655d722cSMark Salyzyn {
2568655d722cSMark Salyzyn 	int status;
2569655d722cSMark Salyzyn 	struct fib *cmd_fibcontext;
2570655d722cSMark Salyzyn 	struct aac_power_management *pmcmd;
2571655d722cSMark Salyzyn 	struct scsi_device *sdev = scsicmd->device;
2572655d722cSMark Salyzyn 	struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
2573655d722cSMark Salyzyn 
2574655d722cSMark Salyzyn 	if (!(aac->supplement_adapter_info.SupportedOptions2 &
2575655d722cSMark Salyzyn 	      AAC_OPTION_POWER_MANAGEMENT)) {
2576655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2577655d722cSMark Salyzyn 				  SAM_STAT_GOOD;
2578655d722cSMark Salyzyn 		scsicmd->scsi_done(scsicmd);
2579655d722cSMark Salyzyn 		return 0;
2580655d722cSMark Salyzyn 	}
2581655d722cSMark Salyzyn 
2582655d722cSMark Salyzyn 	if (aac->in_reset)
2583655d722cSMark Salyzyn 		return SCSI_MLQUEUE_HOST_BUSY;
2584655d722cSMark Salyzyn 
2585655d722cSMark Salyzyn 	/*
2586655d722cSMark Salyzyn 	 *	Allocate and initialize a Fib
2587655d722cSMark Salyzyn 	 */
25886bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd);
2589655d722cSMark Salyzyn 
2590655d722cSMark Salyzyn 	aac_fib_init(cmd_fibcontext);
2591655d722cSMark Salyzyn 
2592655d722cSMark Salyzyn 	pmcmd = fib_data(cmd_fibcontext);
2593655d722cSMark Salyzyn 	pmcmd->command = cpu_to_le32(VM_ContainerConfig);
2594655d722cSMark Salyzyn 	pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
2595655d722cSMark Salyzyn 	/* Eject bit ignored, not relevant */
2596655d722cSMark Salyzyn 	pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
2597655d722cSMark Salyzyn 		cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
2598655d722cSMark Salyzyn 	pmcmd->cid = cpu_to_le32(sdev_id(sdev));
2599655d722cSMark Salyzyn 	pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
2600655d722cSMark Salyzyn 		cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
2601655d722cSMark Salyzyn 
2602655d722cSMark Salyzyn 	/*
2603655d722cSMark Salyzyn 	 *	Now send the Fib to the adapter
2604655d722cSMark Salyzyn 	 */
2605655d722cSMark Salyzyn 	status = aac_fib_send(ContainerCommand,
2606655d722cSMark Salyzyn 		  cmd_fibcontext,
2607655d722cSMark Salyzyn 		  sizeof(struct aac_power_management),
2608655d722cSMark Salyzyn 		  FsaNormal,
2609655d722cSMark Salyzyn 		  0, 1,
2610655d722cSMark Salyzyn 		  (fib_callback)aac_start_stop_callback,
2611655d722cSMark Salyzyn 		  (void *)scsicmd);
2612655d722cSMark Salyzyn 
2613655d722cSMark Salyzyn 	/*
2614655d722cSMark Salyzyn 	 *	Check that the command queued to the controller
2615655d722cSMark Salyzyn 	 */
2616655d722cSMark Salyzyn 	if (status == -EINPROGRESS) {
2617655d722cSMark Salyzyn 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2618655d722cSMark Salyzyn 		return 0;
2619655d722cSMark Salyzyn 	}
2620655d722cSMark Salyzyn 
2621655d722cSMark Salyzyn 	aac_fib_complete(cmd_fibcontext);
2622655d722cSMark Salyzyn 	aac_fib_free(cmd_fibcontext);
2623655d722cSMark Salyzyn 	return SCSI_MLQUEUE_HOST_BUSY;
2624655d722cSMark Salyzyn }
2625655d722cSMark Salyzyn 
26261da177e4SLinus Torvalds /**
26271da177e4SLinus Torvalds  *	aac_scsi_cmd()		-	Process SCSI command
26281da177e4SLinus Torvalds  *	@scsicmd:		SCSI command block
26291da177e4SLinus Torvalds  *
26301da177e4SLinus Torvalds  *	Emulate a SCSI command and queue the required request for the
26311da177e4SLinus Torvalds  *	aacraid firmware.
26321da177e4SLinus Torvalds  */
26331da177e4SLinus Torvalds 
26341da177e4SLinus Torvalds int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
26351da177e4SLinus Torvalds {
2636ab5d129fSRaghava Aditya Renukunta 	u32 cid, bus;
26371da177e4SLinus Torvalds 	struct Scsi_Host *host = scsicmd->device->host;
26381da177e4SLinus Torvalds 	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
26391da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
26401da177e4SLinus Torvalds 
264190ee3466SMark Haverkamp 	if (fsa_dev_ptr == NULL)
264290ee3466SMark Haverkamp 		return -1;
26431da177e4SLinus Torvalds 	/*
26441da177e4SLinus Torvalds 	 *	If the bus, id or lun is out of range, return fail
26451da177e4SLinus Torvalds 	 *	Test does not apply to ID 16, the pseudo id for the controller
26461da177e4SLinus Torvalds 	 *	itself.
26471da177e4SLinus Torvalds 	 */
26481a655040SSalyzyn, Mark 	cid = scmd_id(scsicmd);
26491a655040SSalyzyn, Mark 	if (cid != host->this_id) {
26501a655040SSalyzyn, Mark 		if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) {
26511a655040SSalyzyn, Mark 			if((cid >= dev->maximum_num_containers) ||
2652e5718774SMark Haverkamp 					(scsicmd->device->lun != 0)) {
26531da177e4SLinus Torvalds 				scsicmd->result = DID_NO_CONNECT << 16;
2654c4e2fbcaSRaghava Aditya Renukunta 				goto scsi_done_ret;
26551da177e4SLinus Torvalds 			}
26561da177e4SLinus Torvalds 
26571da177e4SLinus Torvalds 			/*
26581da177e4SLinus Torvalds 			 *	If the target container doesn't exist, it may have
26591da177e4SLinus Torvalds 			 *	been newly created
26601da177e4SLinus Torvalds 			 */
2661655d722cSMark Salyzyn 			if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
2662655d722cSMark Salyzyn 			  (fsa_dev_ptr[cid].sense_data.sense_key ==
2663655d722cSMark Salyzyn 			   NOT_READY)) {
26641da177e4SLinus Torvalds 				switch (scsicmd->cmnd[0]) {
2665eb846d9fSHannes Reinecke 				case SERVICE_ACTION_IN_16:
26667a8cf29dSMark Haverkamp 					if (!(dev->raw_io_interface) ||
26677a8cf29dSMark Haverkamp 					    !(dev->raw_io_64) ||
26687a8cf29dSMark Haverkamp 					    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
26697a8cf29dSMark Haverkamp 						break;
26701da177e4SLinus Torvalds 				case INQUIRY:
26711da177e4SLinus Torvalds 				case READ_CAPACITY:
26721da177e4SLinus Torvalds 				case TEST_UNIT_READY:
26738c867b25SMark Haverkamp 					if (dev->in_reset)
26748c867b25SMark Haverkamp 						return -1;
2675fe76df42SMark Haverkamp 					return _aac_probe_container(scsicmd,
2676fe76df42SMark Haverkamp 							aac_probe_container_callback2);
26771da177e4SLinus Torvalds 				default:
26781da177e4SLinus Torvalds 					break;
26791da177e4SLinus Torvalds 				}
26801da177e4SLinus Torvalds 			}
26811da177e4SLinus Torvalds 		} else {  /* check for physical non-dasd devices */
2682ab5d129fSRaghava Aditya Renukunta 			bus = aac_logical_to_phys(scmd_channel(scsicmd));
2683ab5d129fSRaghava Aditya Renukunta 			if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS &&
2684ab5d129fSRaghava Aditya Renukunta 				(dev->hba_map[bus][cid].expose
2685ab5d129fSRaghava Aditya Renukunta 						== AAC_HIDE_DISK)){
2686ab5d129fSRaghava Aditya Renukunta 				if (scsicmd->cmnd[0] == INQUIRY) {
2687ab5d129fSRaghava Aditya Renukunta 					scsicmd->result = DID_NO_CONNECT << 16;
2688ab5d129fSRaghava Aditya Renukunta 					goto scsi_done_ret;
2689ab5d129fSRaghava Aditya Renukunta 				}
2690ab5d129fSRaghava Aditya Renukunta 			}
2691ab5d129fSRaghava Aditya Renukunta 
2692ab5d129fSRaghava Aditya Renukunta 			if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS &&
2693ab5d129fSRaghava Aditya Renukunta 				dev->hba_map[bus][cid].devtype
2694ab5d129fSRaghava Aditya Renukunta 					== AAC_DEVTYPE_NATIVE_RAW) {
2695ab5d129fSRaghava Aditya Renukunta 				if (dev->in_reset)
2696ab5d129fSRaghava Aditya Renukunta 					return -1;
2697ab5d129fSRaghava Aditya Renukunta 				return aac_send_hba_fib(scsicmd);
2698ab5d129fSRaghava Aditya Renukunta 			} else if (dev->nondasd_support || expose_physicals ||
2699cb1042f2SSalyzyn, Mark 				dev->jbod) {
27008c867b25SMark Haverkamp 				if (dev->in_reset)
27018c867b25SMark Haverkamp 					return -1;
27021da177e4SLinus Torvalds 				return aac_send_srb_fib(scsicmd);
27031da177e4SLinus Torvalds 			} else {
27041da177e4SLinus Torvalds 				scsicmd->result = DID_NO_CONNECT << 16;
2705c4e2fbcaSRaghava Aditya Renukunta 				goto scsi_done_ret;
27061da177e4SLinus Torvalds 			}
27071da177e4SLinus Torvalds 		}
27081da177e4SLinus Torvalds 	}
27091da177e4SLinus Torvalds 	/*
27101da177e4SLinus Torvalds 	 * else Command for the controller itself
27111da177e4SLinus Torvalds 	 */
27121da177e4SLinus Torvalds 	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
27131da177e4SLinus Torvalds 		(scsicmd->cmnd[0] != TEST_UNIT_READY))
27141da177e4SLinus Torvalds 	{
27151da177e4SLinus Torvalds 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
27161da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
27178e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
27188e31e607SSalyzyn, Mark 		  ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
27198e31e607SSalyzyn, Mark 		  ASENCODE_INVALID_COMMAND, 0, 0);
27201da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
27213ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
27223ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
2723c4e2fbcaSRaghava Aditya Renukunta 		goto scsi_done_ret;
27241da177e4SLinus Torvalds 	}
27251da177e4SLinus Torvalds 
27261da177e4SLinus Torvalds 	switch (scsicmd->cmnd[0]) {
2727c4e2fbcaSRaghava Aditya Renukunta 	case READ_6:
2728c4e2fbcaSRaghava Aditya Renukunta 	case READ_10:
2729c4e2fbcaSRaghava Aditya Renukunta 	case READ_12:
2730c4e2fbcaSRaghava Aditya Renukunta 	case READ_16:
2731c4e2fbcaSRaghava Aditya Renukunta 		if (dev->in_reset)
2732c4e2fbcaSRaghava Aditya Renukunta 			return -1;
2733c4e2fbcaSRaghava Aditya Renukunta 		return aac_read(scsicmd);
2734c4e2fbcaSRaghava Aditya Renukunta 
2735c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_6:
2736c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_10:
2737c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_12:
2738c4e2fbcaSRaghava Aditya Renukunta 	case WRITE_16:
2739c4e2fbcaSRaghava Aditya Renukunta 		if (dev->in_reset)
2740c4e2fbcaSRaghava Aditya Renukunta 			return -1;
2741c4e2fbcaSRaghava Aditya Renukunta 		return aac_write(scsicmd);
2742c4e2fbcaSRaghava Aditya Renukunta 
2743c4e2fbcaSRaghava Aditya Renukunta 	case SYNCHRONIZE_CACHE:
2744c4e2fbcaSRaghava Aditya Renukunta 		if (((aac_cache & 6) == 6) && dev->cache_protected) {
2745c4e2fbcaSRaghava Aditya Renukunta 			scsicmd->result = AAC_STAT_GOOD;
2746c4e2fbcaSRaghava Aditya Renukunta 			break;
2747c4e2fbcaSRaghava Aditya Renukunta 		}
2748c4e2fbcaSRaghava Aditya Renukunta 		/* Issue FIB to tell Firmware to flush it's cache */
2749c4e2fbcaSRaghava Aditya Renukunta 		if ((aac_cache & 6) != 2)
2750c4e2fbcaSRaghava Aditya Renukunta 			return aac_synchronize(scsicmd);
27511da177e4SLinus Torvalds 	case INQUIRY:
27521da177e4SLinus Torvalds 	{
27533b2946ccSMark Haverkamp 		struct inquiry_data inq_data;
27541da177e4SLinus Torvalds 
27551a655040SSalyzyn, Mark 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
27563b2946ccSMark Haverkamp 		memset(&inq_data, 0, sizeof (struct inquiry_data));
27571da177e4SLinus Torvalds 
2758d8e96507SLeubner, Achim 		if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) {
275988e2f98eSSalyzyn, Mark 			char *arr = (char *)&inq_data;
276088e2f98eSSalyzyn, Mark 
276188e2f98eSSalyzyn, Mark 			/* EVPD bit set */
276288e2f98eSSalyzyn, Mark 			arr[0] = (scmd_id(scsicmd) == host->this_id) ?
276388e2f98eSSalyzyn, Mark 			  INQD_PDT_PROC : INQD_PDT_DA;
276488e2f98eSSalyzyn, Mark 			if (scsicmd->cmnd[2] == 0) {
276588e2f98eSSalyzyn, Mark 				/* supported vital product data pages */
27665d910649SMahesh Rajashekhara 				arr[3] = 3;
276788e2f98eSSalyzyn, Mark 				arr[4] = 0x0;
276888e2f98eSSalyzyn, Mark 				arr[5] = 0x80;
27695d910649SMahesh Rajashekhara 				arr[6] = 0x83;
277088e2f98eSSalyzyn, Mark 				arr[1] = scsicmd->cmnd[2];
2771d4345028SFUJITA Tomonori 				scsi_sg_copy_from_buffer(scsicmd, &inq_data,
277288e2f98eSSalyzyn, Mark 							 sizeof(inq_data));
2773c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->result = AAC_STAT_GOOD;
277488e2f98eSSalyzyn, Mark 			} else if (scsicmd->cmnd[2] == 0x80) {
277588e2f98eSSalyzyn, Mark 				/* unit serial number page */
277688e2f98eSSalyzyn, Mark 				arr[3] = setinqserial(dev, &arr[4],
277788e2f98eSSalyzyn, Mark 				  scmd_id(scsicmd));
277888e2f98eSSalyzyn, Mark 				arr[1] = scsicmd->cmnd[2];
2779d4345028SFUJITA Tomonori 				scsi_sg_copy_from_buffer(scsicmd, &inq_data,
278088e2f98eSSalyzyn, Mark 							 sizeof(inq_data));
2781d8e96507SLeubner, Achim 				if (aac_wwn != 2)
2782d8e96507SLeubner, Achim 					return aac_get_container_serial(
2783d8e96507SLeubner, Achim 						scsicmd);
2784c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->result = AAC_STAT_GOOD;
27855d910649SMahesh Rajashekhara 			} else if (scsicmd->cmnd[2] == 0x83) {
27865d910649SMahesh Rajashekhara 				/* vpd page 0x83 - Device Identification Page */
27875d910649SMahesh Rajashekhara 				char *sno = (char *)&inq_data;
27885d910649SMahesh Rajashekhara 				sno[3] = setinqserial(dev, &sno[4],
27895d910649SMahesh Rajashekhara 						      scmd_id(scsicmd));
27905d910649SMahesh Rajashekhara 				if (aac_wwn != 2)
27915d910649SMahesh Rajashekhara 					return aac_get_container_serial(
27925d910649SMahesh Rajashekhara 						scsicmd);
2793c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->result = AAC_STAT_GOOD;
279488e2f98eSSalyzyn, Mark 			} else {
279588e2f98eSSalyzyn, Mark 				/* vpd page not implemented */
279688e2f98eSSalyzyn, Mark 				scsicmd->result = DID_OK << 16 |
279788e2f98eSSalyzyn, Mark 				  COMMAND_COMPLETE << 8 |
279888e2f98eSSalyzyn, Mark 				  SAM_STAT_CHECK_CONDITION;
27998e31e607SSalyzyn, Mark 				set_sense(&dev->fsa_dev[cid].sense_data,
28008e31e607SSalyzyn, Mark 				  ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD,
28018e31e607SSalyzyn, Mark 				  ASENCODE_NO_SENSE, 7, 2);
280288e2f98eSSalyzyn, Mark 				memcpy(scsicmd->sense_buffer,
280388e2f98eSSalyzyn, Mark 				  &dev->fsa_dev[cid].sense_data,
28043ace426fSSalyzyn, Mark 				  min_t(size_t,
28053ace426fSSalyzyn, Mark 					sizeof(dev->fsa_dev[cid].sense_data),
28063ace426fSSalyzyn, Mark 					SCSI_SENSE_BUFFERSIZE));
280788e2f98eSSalyzyn, Mark 			}
2808c4e2fbcaSRaghava Aditya Renukunta 			break;
280988e2f98eSSalyzyn, Mark 		}
28103b2946ccSMark Haverkamp 		inq_data.inqd_ver = 2;	/* claim compliance to SCSI-2 */
28113b2946ccSMark 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 */
28123b2946ccSMark Haverkamp 		inq_data.inqd_len = 31;
28131da177e4SLinus Torvalds 		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
28143b2946ccSMark Haverkamp 		inq_data.inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
28151da177e4SLinus Torvalds 		/*
28161da177e4SLinus Torvalds 		 *	Set the Vendor, Product, and Revision Level
28171da177e4SLinus Torvalds 		 *	see: <vendor>.c i.e. aac.c
28181da177e4SLinus Torvalds 		 */
28191a655040SSalyzyn, Mark 		if (cid == host->this_id) {
28206391a113STobias Klauser 			setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
28213b2946ccSMark Haverkamp 			inq_data.inqd_pdt = INQD_PDT_PROC;	/* Processor device */
2822d4345028SFUJITA Tomonori 			scsi_sg_copy_from_buffer(scsicmd, &inq_data,
2823d4345028SFUJITA Tomonori 						 sizeof(inq_data));
2824c4e2fbcaSRaghava Aditya Renukunta 			scsicmd->result = AAC_STAT_GOOD;
2825c4e2fbcaSRaghava Aditya Renukunta 			break;
28261da177e4SLinus Torvalds 		}
28278c867b25SMark Haverkamp 		if (dev->in_reset)
28288c867b25SMark Haverkamp 			return -1;
2829794d0601SMark Haverkamp 		setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
28303b2946ccSMark Haverkamp 		inq_data.inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
2831d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
28329e7c349cSMark Haverkamp 		return aac_get_container_name(scsicmd);
28331da177e4SLinus Torvalds 	}
2834eb846d9fSHannes Reinecke 	case SERVICE_ACTION_IN_16:
28357a8cf29dSMark Haverkamp 		if (!(dev->raw_io_interface) ||
28367a8cf29dSMark Haverkamp 		    !(dev->raw_io_64) ||
28377a8cf29dSMark Haverkamp 		    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
28387a8cf29dSMark Haverkamp 			break;
28397a8cf29dSMark Haverkamp 	{
28407a8cf29dSMark Haverkamp 		u64 capacity;
284107ce5ebaSMark Haverkamp 		char cp[13];
2842b271f1c8SFUJITA Tomonori 		unsigned int alloc_len;
28437a8cf29dSMark Haverkamp 
28447a8cf29dSMark Haverkamp 		dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
28457a8cf29dSMark Haverkamp 		capacity = fsa_dev_ptr[cid].size - 1;
28467a8cf29dSMark Haverkamp 		cp[0] = (capacity >> 56) & 0xff;
28477a8cf29dSMark Haverkamp 		cp[1] = (capacity >> 48) & 0xff;
28487a8cf29dSMark Haverkamp 		cp[2] = (capacity >> 40) & 0xff;
28497a8cf29dSMark Haverkamp 		cp[3] = (capacity >> 32) & 0xff;
28507a8cf29dSMark Haverkamp 		cp[4] = (capacity >> 24) & 0xff;
28517a8cf29dSMark Haverkamp 		cp[5] = (capacity >> 16) & 0xff;
28527a8cf29dSMark Haverkamp 		cp[6] = (capacity >> 8) & 0xff;
28537a8cf29dSMark Haverkamp 		cp[7] = (capacity >> 0) & 0xff;
2854b836439fSMahesh Rajashekhara 		cp[8] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff;
2855b836439fSMahesh Rajashekhara 		cp[9] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2856b836439fSMahesh Rajashekhara 		cp[10] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff;
2857b836439fSMahesh Rajashekhara 		cp[11] = (fsa_dev_ptr[cid].block_size) & 0xff;
285807ce5ebaSMark Haverkamp 		cp[12] = 0;
285907ce5ebaSMark Haverkamp 
2860b271f1c8SFUJITA Tomonori 		alloc_len = ((scsicmd->cmnd[10] << 24)
2861b271f1c8SFUJITA Tomonori 			     + (scsicmd->cmnd[11] << 16)
2862b271f1c8SFUJITA Tomonori 			     + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]);
2863b271f1c8SFUJITA Tomonori 
2864b271f1c8SFUJITA Tomonori 		alloc_len = min_t(size_t, alloc_len, sizeof(cp));
2865d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len);
2866b271f1c8SFUJITA Tomonori 		if (alloc_len < scsi_bufflen(scsicmd))
2867b271f1c8SFUJITA Tomonori 			scsi_set_resid(scsicmd,
2868b271f1c8SFUJITA Tomonori 				       scsi_bufflen(scsicmd) - alloc_len);
28697a8cf29dSMark Haverkamp 
28707a8cf29dSMark Haverkamp 		/* Do not cache partition table for arrays */
28717a8cf29dSMark Haverkamp 		scsicmd->device->removable = 1;
28727a8cf29dSMark Haverkamp 
2873c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2874c4e2fbcaSRaghava Aditya Renukunta 		break;
28757a8cf29dSMark Haverkamp 	}
28767a8cf29dSMark Haverkamp 
28771da177e4SLinus Torvalds 	case READ_CAPACITY:
28781da177e4SLinus Torvalds 	{
28791da177e4SLinus Torvalds 		u32 capacity;
28803b2946ccSMark Haverkamp 		char cp[8];
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
28837a8cf29dSMark Haverkamp 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
28841da177e4SLinus Torvalds 			capacity = fsa_dev_ptr[cid].size - 1;
28851da177e4SLinus Torvalds 		else
28861da177e4SLinus Torvalds 			capacity = (u32)-1;
28873b2946ccSMark Haverkamp 
28881da177e4SLinus Torvalds 		cp[0] = (capacity >> 24) & 0xff;
28891da177e4SLinus Torvalds 		cp[1] = (capacity >> 16) & 0xff;
28901da177e4SLinus Torvalds 		cp[2] = (capacity >> 8) & 0xff;
28911da177e4SLinus Torvalds 		cp[3] = (capacity >> 0) & 0xff;
2892b836439fSMahesh Rajashekhara 		cp[4] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff;
2893b836439fSMahesh Rajashekhara 		cp[5] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2894b836439fSMahesh Rajashekhara 		cp[6] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff;
2895b836439fSMahesh Rajashekhara 		cp[7] = (fsa_dev_ptr[cid].block_size) & 0xff;
2896d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
28977a8cf29dSMark Haverkamp 		/* Do not cache partition table for arrays */
28987a8cf29dSMark Haverkamp 		scsicmd->device->removable = 1;
2899c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2900c4e2fbcaSRaghava Aditya Renukunta 		break;
29011da177e4SLinus Torvalds 	}
29021da177e4SLinus Torvalds 
29031da177e4SLinus Torvalds 	case MODE_SENSE:
29041da177e4SLinus Torvalds 	{
29059d399cc7SSalyzyn, Mark 		int mode_buf_length = 4;
2906b836439fSMahesh Rajashekhara 		u32 capacity;
2907b836439fSMahesh Rajashekhara 		aac_modep_data mpd;
2908b836439fSMahesh Rajashekhara 
2909b836439fSMahesh Rajashekhara 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
2910b836439fSMahesh Rajashekhara 			capacity = fsa_dev_ptr[cid].size - 1;
2911b836439fSMahesh Rajashekhara 		else
2912b836439fSMahesh Rajashekhara 			capacity = (u32)-1;
29131da177e4SLinus Torvalds 
29141da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "MODE SENSE command.\n"));
2915b836439fSMahesh Rajashekhara 		memset((char *)&mpd, 0, sizeof(aac_modep_data));
2916b836439fSMahesh Rajashekhara 
2917b836439fSMahesh Rajashekhara 		/* Mode data length */
2918b836439fSMahesh Rajashekhara 		mpd.hd.data_length = sizeof(mpd.hd) - 1;
2919b836439fSMahesh Rajashekhara 		/* Medium type - default */
2920b836439fSMahesh Rajashekhara 		mpd.hd.med_type = 0;
2921b836439fSMahesh Rajashekhara 		/* Device-specific param,
29229d399cc7SSalyzyn, Mark 		   bit 8: 0/1 = write enabled/protected
29239d399cc7SSalyzyn, Mark 		   bit 4: 0/1 = FUA enabled */
2924b836439fSMahesh Rajashekhara 		mpd.hd.dev_par = 0;
2925b836439fSMahesh Rajashekhara 
292695e852e1SSalyzyn, Mark 		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
2927b836439fSMahesh Rajashekhara 			mpd.hd.dev_par = 0x10;
2928b836439fSMahesh Rajashekhara 		if (scsicmd->cmnd[1] & 0x8)
2929b836439fSMahesh Rajashekhara 			mpd.hd.bd_length = 0;	/* Block descriptor length */
2930b836439fSMahesh Rajashekhara 		else {
2931b836439fSMahesh Rajashekhara 			mpd.hd.bd_length = sizeof(mpd.bd);
2932b836439fSMahesh Rajashekhara 			mpd.hd.data_length += mpd.hd.bd_length;
2933b836439fSMahesh Rajashekhara 			mpd.bd.block_length[0] =
2934b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 16) & 0xff;
2935b836439fSMahesh Rajashekhara 			mpd.bd.block_length[1] =
2936b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 8) &  0xff;
2937b836439fSMahesh Rajashekhara 			mpd.bd.block_length[2] =
2938b836439fSMahesh Rajashekhara 				fsa_dev_ptr[cid].block_size  & 0xff;
29395d910649SMahesh Rajashekhara 
29405d910649SMahesh Rajashekhara 			mpd.mpc_buf[0] = scsicmd->cmnd[2];
29415d910649SMahesh Rajashekhara 			if (scsicmd->cmnd[2] == 0x1C) {
29425d910649SMahesh Rajashekhara 				/* page length */
29435d910649SMahesh Rajashekhara 				mpd.mpc_buf[1] = 0xa;
29445d910649SMahesh Rajashekhara 				/* Mode data length */
29455d910649SMahesh Rajashekhara 				mpd.hd.data_length = 23;
29465d910649SMahesh Rajashekhara 			} else {
29475d910649SMahesh Rajashekhara 				/* Mode data length */
29485d910649SMahesh Rajashekhara 				mpd.hd.data_length = 15;
29495d910649SMahesh Rajashekhara 			}
29505d910649SMahesh Rajashekhara 
2951b836439fSMahesh Rajashekhara 			if (capacity > 0xffffff) {
2952b836439fSMahesh Rajashekhara 				mpd.bd.block_count[0] = 0xff;
2953b836439fSMahesh Rajashekhara 				mpd.bd.block_count[1] = 0xff;
2954b836439fSMahesh Rajashekhara 				mpd.bd.block_count[2] = 0xff;
2955b836439fSMahesh Rajashekhara 			} else {
2956b836439fSMahesh Rajashekhara 				mpd.bd.block_count[0] = (capacity >> 16) & 0xff;
2957b836439fSMahesh Rajashekhara 				mpd.bd.block_count[1] = (capacity >> 8) & 0xff;
2958b836439fSMahesh Rajashekhara 				mpd.bd.block_count[2] = capacity  & 0xff;
2959b836439fSMahesh Rajashekhara 			}
2960b836439fSMahesh Rajashekhara 		}
29619d399cc7SSalyzyn, Mark 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
29629d399cc7SSalyzyn, Mark 		  ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
2963b836439fSMahesh Rajashekhara 			mpd.hd.data_length += 3;
2964b836439fSMahesh Rajashekhara 			mpd.mpc_buf[0] = 8;
2965b836439fSMahesh Rajashekhara 			mpd.mpc_buf[1] = 1;
2966b836439fSMahesh Rajashekhara 			mpd.mpc_buf[2] = ((aac_cache & 6) == 2)
296795e852e1SSalyzyn, Mark 				? 0 : 0x04; /* WCE */
2968b836439fSMahesh Rajashekhara 			mode_buf_length = sizeof(mpd);
29695d910649SMahesh Rajashekhara 		}
29705d910649SMahesh Rajashekhara 
29719d399cc7SSalyzyn, Mark 		if (mode_buf_length > scsicmd->cmnd[4])
29729d399cc7SSalyzyn, Mark 			mode_buf_length = scsicmd->cmnd[4];
29735d910649SMahesh Rajashekhara 		else
29745d910649SMahesh Rajashekhara 			mode_buf_length = sizeof(mpd);
2975b836439fSMahesh Rajashekhara 		scsi_sg_copy_from_buffer(scsicmd,
2976b836439fSMahesh Rajashekhara 					 (char *)&mpd,
2977b836439fSMahesh Rajashekhara 					 mode_buf_length);
2978c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
2979c4e2fbcaSRaghava Aditya Renukunta 		break;
29801da177e4SLinus Torvalds 	}
29811da177e4SLinus Torvalds 	case MODE_SENSE_10:
29821da177e4SLinus Torvalds 	{
2983b836439fSMahesh Rajashekhara 		u32 capacity;
29849d399cc7SSalyzyn, Mark 		int mode_buf_length = 8;
2985b836439fSMahesh Rajashekhara 		aac_modep10_data mpd10;
2986b836439fSMahesh Rajashekhara 
2987b836439fSMahesh Rajashekhara 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
2988b836439fSMahesh Rajashekhara 			capacity = fsa_dev_ptr[cid].size - 1;
2989b836439fSMahesh Rajashekhara 		else
2990b836439fSMahesh Rajashekhara 			capacity = (u32)-1;
29911da177e4SLinus Torvalds 
29921da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
2993b836439fSMahesh Rajashekhara 		memset((char *)&mpd10, 0, sizeof(aac_modep10_data));
2994b836439fSMahesh Rajashekhara 		/* Mode data length (MSB) */
2995b836439fSMahesh Rajashekhara 		mpd10.hd.data_length[0] = 0;
2996b836439fSMahesh Rajashekhara 		/* Mode data length (LSB) */
2997b836439fSMahesh Rajashekhara 		mpd10.hd.data_length[1] = sizeof(mpd10.hd) - 1;
2998b836439fSMahesh Rajashekhara 		/* Medium type - default */
2999b836439fSMahesh Rajashekhara 		mpd10.hd.med_type = 0;
3000b836439fSMahesh Rajashekhara 		/* Device-specific param,
30019d399cc7SSalyzyn, Mark 		   bit 8: 0/1 = write enabled/protected
30029d399cc7SSalyzyn, Mark 		   bit 4: 0/1 = FUA enabled */
3003b836439fSMahesh Rajashekhara 		mpd10.hd.dev_par = 0;
3004b836439fSMahesh Rajashekhara 
300595e852e1SSalyzyn, Mark 		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
3006b836439fSMahesh Rajashekhara 			mpd10.hd.dev_par = 0x10;
3007b836439fSMahesh Rajashekhara 		mpd10.hd.rsrvd[0] = 0;	/* reserved */
3008b836439fSMahesh Rajashekhara 		mpd10.hd.rsrvd[1] = 0;	/* reserved */
3009b836439fSMahesh Rajashekhara 		if (scsicmd->cmnd[1] & 0x8) {
3010b836439fSMahesh Rajashekhara 			/* Block descriptor length (MSB) */
3011b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[0] = 0;
3012b836439fSMahesh Rajashekhara 			/* Block descriptor length (LSB) */
3013b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[1] = 0;
3014b836439fSMahesh Rajashekhara 		} else {
3015b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[0] = 0;
3016b836439fSMahesh Rajashekhara 			mpd10.hd.bd_length[1] = sizeof(mpd10.bd);
3017b836439fSMahesh Rajashekhara 
3018b836439fSMahesh Rajashekhara 			mpd10.hd.data_length[1] += mpd10.hd.bd_length[1];
3019b836439fSMahesh Rajashekhara 
3020b836439fSMahesh Rajashekhara 			mpd10.bd.block_length[0] =
3021b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 16) & 0xff;
3022b836439fSMahesh Rajashekhara 			mpd10.bd.block_length[1] =
3023b836439fSMahesh Rajashekhara 				(fsa_dev_ptr[cid].block_size >> 8) & 0xff;
3024b836439fSMahesh Rajashekhara 			mpd10.bd.block_length[2] =
3025b836439fSMahesh Rajashekhara 				fsa_dev_ptr[cid].block_size  & 0xff;
3026b836439fSMahesh Rajashekhara 
3027b836439fSMahesh Rajashekhara 			if (capacity > 0xffffff) {
3028b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[0] = 0xff;
3029b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[1] = 0xff;
3030b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[2] = 0xff;
3031b836439fSMahesh Rajashekhara 			} else {
3032b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[0] =
3033b836439fSMahesh Rajashekhara 					(capacity >> 16) & 0xff;
3034b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[1] =
3035b836439fSMahesh Rajashekhara 					(capacity >> 8) & 0xff;
3036b836439fSMahesh Rajashekhara 				mpd10.bd.block_count[2] =
3037b836439fSMahesh Rajashekhara 					capacity  & 0xff;
3038b836439fSMahesh Rajashekhara 			}
3039b836439fSMahesh Rajashekhara 		}
30409d399cc7SSalyzyn, Mark 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
30419d399cc7SSalyzyn, Mark 		  ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
3042b836439fSMahesh Rajashekhara 			mpd10.hd.data_length[1] += 3;
3043b836439fSMahesh Rajashekhara 			mpd10.mpc_buf[0] = 8;
3044b836439fSMahesh Rajashekhara 			mpd10.mpc_buf[1] = 1;
3045b836439fSMahesh Rajashekhara 			mpd10.mpc_buf[2] = ((aac_cache & 6) == 2)
304695e852e1SSalyzyn, Mark 				? 0 : 0x04; /* WCE */
3047b836439fSMahesh Rajashekhara 			mode_buf_length = sizeof(mpd10);
30489d399cc7SSalyzyn, Mark 			if (mode_buf_length > scsicmd->cmnd[8])
30499d399cc7SSalyzyn, Mark 				mode_buf_length = scsicmd->cmnd[8];
30509d399cc7SSalyzyn, Mark 		}
3051b836439fSMahesh Rajashekhara 		scsi_sg_copy_from_buffer(scsicmd,
3052b836439fSMahesh Rajashekhara 					 (char *)&mpd10,
3053b836439fSMahesh Rajashekhara 					 mode_buf_length);
30541da177e4SLinus Torvalds 
3055c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
3056c4e2fbcaSRaghava Aditya Renukunta 		break;
30571da177e4SLinus Torvalds 	}
30581da177e4SLinus Torvalds 	case REQUEST_SENSE:
30591da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
3060c4e2fbcaSRaghava Aditya Renukunta 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
3061c4e2fbcaSRaghava Aditya Renukunta 				sizeof(struct sense_data));
3062c4e2fbcaSRaghava Aditya Renukunta 		memset(&dev->fsa_dev[cid].sense_data, 0,
3063c4e2fbcaSRaghava Aditya Renukunta 				sizeof(struct sense_data));
3064c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
3065c4e2fbcaSRaghava Aditya Renukunta 		break;
30661da177e4SLinus Torvalds 
30671da177e4SLinus Torvalds 	case ALLOW_MEDIUM_REMOVAL:
30681da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "LOCK command.\n"));
30691da177e4SLinus Torvalds 		if (scsicmd->cmnd[4])
30701da177e4SLinus Torvalds 			fsa_dev_ptr[cid].locked = 1;
30711da177e4SLinus Torvalds 		else
30721da177e4SLinus Torvalds 			fsa_dev_ptr[cid].locked = 0;
30731da177e4SLinus Torvalds 
3074c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
3075c4e2fbcaSRaghava Aditya Renukunta 		break;
30761da177e4SLinus Torvalds 	/*
30771da177e4SLinus Torvalds 	 *	These commands are all No-Ops
30781da177e4SLinus Torvalds 	 */
30791da177e4SLinus Torvalds 	case TEST_UNIT_READY:
3080655d722cSMark Salyzyn 		if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
3081655d722cSMark Salyzyn 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
3082655d722cSMark Salyzyn 				SAM_STAT_CHECK_CONDITION;
3083655d722cSMark Salyzyn 			set_sense(&dev->fsa_dev[cid].sense_data,
3084655d722cSMark Salyzyn 				  NOT_READY, SENCODE_BECOMING_READY,
3085655d722cSMark Salyzyn 				  ASENCODE_BECOMING_READY, 0, 0);
3086655d722cSMark Salyzyn 			memcpy(scsicmd->sense_buffer,
3087655d722cSMark Salyzyn 			       &dev->fsa_dev[cid].sense_data,
3088655d722cSMark Salyzyn 			       min_t(size_t,
3089655d722cSMark Salyzyn 				     sizeof(dev->fsa_dev[cid].sense_data),
3090655d722cSMark Salyzyn 				     SCSI_SENSE_BUFFERSIZE));
3091c4e2fbcaSRaghava Aditya Renukunta 		break;
3092655d722cSMark Salyzyn 		}
30931da177e4SLinus Torvalds 	case RESERVE:
30941da177e4SLinus Torvalds 	case RELEASE:
30951da177e4SLinus Torvalds 	case REZERO_UNIT:
30961da177e4SLinus Torvalds 	case REASSIGN_BLOCKS:
30971da177e4SLinus Torvalds 	case SEEK_10:
3098c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = AAC_STAT_GOOD;
3099c4e2fbcaSRaghava Aditya Renukunta 		break;
3100655d722cSMark Salyzyn 
3101655d722cSMark Salyzyn 	case START_STOP:
3102655d722cSMark Salyzyn 		return aac_start_stop(scsicmd);
31031da177e4SLinus Torvalds 
310495e852e1SSalyzyn, Mark 	/* FALLTHRU */
31051da177e4SLinus Torvalds 	default:
31061da177e4SLinus Torvalds 	/*
31071da177e4SLinus Torvalds 	 *	Unhandled commands
31081da177e4SLinus Torvalds 	 */
3109c4e2fbcaSRaghava Aditya Renukunta 		dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n",
3110c4e2fbcaSRaghava Aditya Renukunta 				scsicmd->cmnd[0]));
3111c4e2fbcaSRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
3112c4e2fbcaSRaghava Aditya Renukunta 				SAM_STAT_CHECK_CONDITION;
31138e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
31141da177e4SLinus Torvalds 			  ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
31158e31e607SSalyzyn, Mark 			  ASENCODE_INVALID_COMMAND, 0, 0);
31161da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
31173ace426fSSalyzyn, Mark 				min_t(size_t,
31183ace426fSSalyzyn, Mark 				      sizeof(dev->fsa_dev[cid].sense_data),
31193ace426fSSalyzyn, Mark 				      SCSI_SENSE_BUFFERSIZE));
3120c4e2fbcaSRaghava Aditya Renukunta 	}
3121c4e2fbcaSRaghava Aditya Renukunta 
3122c4e2fbcaSRaghava Aditya Renukunta scsi_done_ret:
3123c4e2fbcaSRaghava Aditya Renukunta 
31241da177e4SLinus Torvalds 	scsicmd->scsi_done(scsicmd);
31251da177e4SLinus Torvalds 	return 0;
31261da177e4SLinus Torvalds }
31271da177e4SLinus Torvalds 
31281da177e4SLinus Torvalds static int query_disk(struct aac_dev *dev, void __user *arg)
31291da177e4SLinus Torvalds {
31301da177e4SLinus Torvalds 	struct aac_query_disk qd;
31311da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
31321da177e4SLinus Torvalds 
31331da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
313490ee3466SMark Haverkamp 	if (!fsa_dev_ptr)
313565101355SMark Haverkamp 		return -EBUSY;
31361da177e4SLinus Torvalds 	if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
31371da177e4SLinus Torvalds 		return -EFAULT;
31381da177e4SLinus Torvalds 	if (qd.cnum == -1)
3139e5718774SMark Haverkamp 		qd.cnum = qd.id;
31401da177e4SLinus Torvalds 	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
31411da177e4SLinus Torvalds 	{
31421da177e4SLinus Torvalds 		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
31431da177e4SLinus Torvalds 			return -EINVAL;
31441da177e4SLinus Torvalds 		qd.instance = dev->scsi_host_ptr->host_no;
31451da177e4SLinus Torvalds 		qd.bus = 0;
31461da177e4SLinus Torvalds 		qd.id = CONTAINER_TO_ID(qd.cnum);
31471da177e4SLinus Torvalds 		qd.lun = CONTAINER_TO_LUN(qd.cnum);
31481da177e4SLinus Torvalds 	}
31491da177e4SLinus Torvalds 	else return -EINVAL;
31501da177e4SLinus Torvalds 
3151fd622b1bSSalyzyn, Mark 	qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
31521da177e4SLinus Torvalds 	qd.locked = fsa_dev_ptr[qd.cnum].locked;
31531da177e4SLinus Torvalds 	qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
31541da177e4SLinus Torvalds 
31551da177e4SLinus Torvalds 	if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
31561da177e4SLinus Torvalds 		qd.unmapped = 1;
31571da177e4SLinus Torvalds 	else
31581da177e4SLinus Torvalds 		qd.unmapped = 0;
31591da177e4SLinus Torvalds 
31601da177e4SLinus Torvalds 	strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
31611da177e4SLinus Torvalds 	  min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
31621da177e4SLinus Torvalds 
31631da177e4SLinus Torvalds 	if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
31641da177e4SLinus Torvalds 		return -EFAULT;
31651da177e4SLinus Torvalds 	return 0;
31661da177e4SLinus Torvalds }
31671da177e4SLinus Torvalds 
31681da177e4SLinus Torvalds static int force_delete_disk(struct aac_dev *dev, void __user *arg)
31691da177e4SLinus Torvalds {
31701da177e4SLinus Torvalds 	struct aac_delete_disk dd;
31711da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
31721da177e4SLinus Torvalds 
31731da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
317465101355SMark Haverkamp 	if (!fsa_dev_ptr)
317565101355SMark Haverkamp 		return -EBUSY;
31761da177e4SLinus Torvalds 
31771da177e4SLinus Torvalds 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
31781da177e4SLinus Torvalds 		return -EFAULT;
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 	if (dd.cnum >= dev->maximum_num_containers)
31811da177e4SLinus Torvalds 		return -EINVAL;
31821da177e4SLinus Torvalds 	/*
31831da177e4SLinus Torvalds 	 *	Mark this container as being deleted.
31841da177e4SLinus Torvalds 	 */
31851da177e4SLinus Torvalds 	fsa_dev_ptr[dd.cnum].deleted = 1;
31861da177e4SLinus Torvalds 	/*
31871da177e4SLinus Torvalds 	 *	Mark the container as no longer valid
31881da177e4SLinus Torvalds 	 */
31891da177e4SLinus Torvalds 	fsa_dev_ptr[dd.cnum].valid = 0;
31901da177e4SLinus Torvalds 	return 0;
31911da177e4SLinus Torvalds }
31921da177e4SLinus Torvalds 
31931da177e4SLinus Torvalds static int delete_disk(struct aac_dev *dev, void __user *arg)
31941da177e4SLinus Torvalds {
31951da177e4SLinus Torvalds 	struct aac_delete_disk dd;
31961da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
31971da177e4SLinus Torvalds 
31981da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
319990ee3466SMark Haverkamp 	if (!fsa_dev_ptr)
320065101355SMark Haverkamp 		return -EBUSY;
32011da177e4SLinus Torvalds 
32021da177e4SLinus Torvalds 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
32031da177e4SLinus Torvalds 		return -EFAULT;
32041da177e4SLinus Torvalds 
32051da177e4SLinus Torvalds 	if (dd.cnum >= dev->maximum_num_containers)
32061da177e4SLinus Torvalds 		return -EINVAL;
32071da177e4SLinus Torvalds 	/*
32081da177e4SLinus Torvalds 	 *	If the container is locked, it can not be deleted by the API.
32091da177e4SLinus Torvalds 	 */
32101da177e4SLinus Torvalds 	if (fsa_dev_ptr[dd.cnum].locked)
32111da177e4SLinus Torvalds 		return -EBUSY;
32121da177e4SLinus Torvalds 	else {
32131da177e4SLinus Torvalds 		/*
32141da177e4SLinus Torvalds 		 *	Mark the container as no longer being valid.
32151da177e4SLinus Torvalds 		 */
32161da177e4SLinus Torvalds 		fsa_dev_ptr[dd.cnum].valid = 0;
32171da177e4SLinus Torvalds 		fsa_dev_ptr[dd.cnum].devname[0] = '\0';
32181da177e4SLinus Torvalds 		return 0;
32191da177e4SLinus Torvalds 	}
32201da177e4SLinus Torvalds }
32211da177e4SLinus Torvalds 
32221da177e4SLinus Torvalds int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
32231da177e4SLinus Torvalds {
32241da177e4SLinus Torvalds 	switch (cmd) {
32251da177e4SLinus Torvalds 	case FSACTL_QUERY_DISK:
32261da177e4SLinus Torvalds 		return query_disk(dev, arg);
32271da177e4SLinus Torvalds 	case FSACTL_DELETE_DISK:
32281da177e4SLinus Torvalds 		return delete_disk(dev, arg);
32291da177e4SLinus Torvalds 	case FSACTL_FORCE_DELETE_DISK:
32301da177e4SLinus Torvalds 		return force_delete_disk(dev, arg);
32311da177e4SLinus Torvalds 	case FSACTL_GET_CONTAINERS:
32321da177e4SLinus Torvalds 		return aac_get_containers(dev);
32331da177e4SLinus Torvalds 	default:
32341da177e4SLinus Torvalds 		return -ENOTTY;
32351da177e4SLinus Torvalds 	}
32361da177e4SLinus Torvalds }
32371da177e4SLinus Torvalds 
32381da177e4SLinus Torvalds /**
32391da177e4SLinus Torvalds  *
32401da177e4SLinus Torvalds  * aac_srb_callback
32411da177e4SLinus Torvalds  * @context: the context set in the fib - here it is scsi cmd
32421da177e4SLinus Torvalds  * @fibptr: pointer to the fib
32431da177e4SLinus Torvalds  *
32441da177e4SLinus Torvalds  * Handles the completion of a scsi command to a non dasd device
32451da177e4SLinus Torvalds  *
32461da177e4SLinus Torvalds  */
32471da177e4SLinus Torvalds 
32481da177e4SLinus Torvalds static void aac_srb_callback(void *context, struct fib * fibptr)
32491da177e4SLinus Torvalds {
32501da177e4SLinus Torvalds 	struct aac_dev *dev;
32511da177e4SLinus Torvalds 	struct aac_srb_reply *srbreply;
32521da177e4SLinus Torvalds 	struct scsi_cmnd *scsicmd;
32531da177e4SLinus Torvalds 
32541da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
325503d44337SMark Haverkamp 
325603d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
325703d44337SMark Haverkamp 		return;
325803d44337SMark Haverkamp 
3259125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
32604ec57fb4SRaghava Aditya Renukunta 
32611a655040SSalyzyn, Mark 	dev = fibptr->dev;
32621a655040SSalyzyn, Mark 
326355b87608SMahesh Rajashekhara 	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
32644ec57fb4SRaghava Aditya Renukunta 
32651da177e4SLinus Torvalds 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
326685d22bbfSMahesh Rajashekhara 
326785d22bbfSMahesh Rajashekhara 	if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
326885d22bbfSMahesh Rajashekhara 		/* fast response */
326985d22bbfSMahesh Rajashekhara 		srbreply->srb_status = cpu_to_le32(SRB_STATUS_SUCCESS);
327085d22bbfSMahesh Rajashekhara 		srbreply->scsi_status = cpu_to_le32(SAM_STAT_GOOD);
327185d22bbfSMahesh Rajashekhara 	} else {
32721da177e4SLinus Torvalds 		/*
32731da177e4SLinus Torvalds 		 *	Calculate resid for sg
32741da177e4SLinus Torvalds 		 */
3275727eead6SFUJITA Tomonori 		scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
3276727eead6SFUJITA Tomonori 				   - le32_to_cpu(srbreply->data_xfer_length));
32774ec57fb4SRaghava Aditya Renukunta 	}
32784ec57fb4SRaghava Aditya Renukunta 
32794ec57fb4SRaghava Aditya Renukunta 
32804ec57fb4SRaghava Aditya Renukunta 	scsi_dma_unmap(scsicmd);
32814ec57fb4SRaghava Aditya Renukunta 
32824ec57fb4SRaghava Aditya Renukunta 	/* expose physical device if expose_physicald flag is on */
32834ec57fb4SRaghava Aditya Renukunta 	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
32844ec57fb4SRaghava Aditya Renukunta 	  && expose_physicals > 0)
32854ec57fb4SRaghava Aditya Renukunta 		aac_expose_phy_device(scsicmd);
32864ec57fb4SRaghava Aditya Renukunta 
32871da177e4SLinus Torvalds 	/*
32881da177e4SLinus Torvalds 	 * First check the fib status
32891da177e4SLinus Torvalds 	 */
32901da177e4SLinus Torvalds 
32911da177e4SLinus Torvalds 	if (le32_to_cpu(srbreply->status) != ST_OK) {
32921da177e4SLinus Torvalds 		int len;
329355b87608SMahesh Rajashekhara 
32944ec57fb4SRaghava Aditya Renukunta 		pr_warn("aac_srb_callback: srb failed, status = %d\n",
32954ec57fb4SRaghava Aditya Renukunta 				le32_to_cpu(srbreply->status));
32963ace426fSSalyzyn, Mark 		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
32973ace426fSSalyzyn, Mark 			    SCSI_SENSE_BUFFERSIZE);
329855b87608SMahesh Rajashekhara 		scsicmd->result = DID_ERROR << 16
329955b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8
330055b87608SMahesh Rajashekhara 				| SAM_STAT_CHECK_CONDITION;
330155b87608SMahesh Rajashekhara 		memcpy(scsicmd->sense_buffer,
330255b87608SMahesh Rajashekhara 				srbreply->sense_data, len);
33031da177e4SLinus Torvalds 	}
33041da177e4SLinus Torvalds 
33051da177e4SLinus Torvalds 	/*
33061da177e4SLinus Torvalds 	 * Next check the srb status
33071da177e4SLinus Torvalds 	 */
33081da177e4SLinus Torvalds 	switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
33091da177e4SLinus Torvalds 	case SRB_STATUS_ERROR_RECOVERY:
33101da177e4SLinus Torvalds 	case SRB_STATUS_PENDING:
33111da177e4SLinus Torvalds 	case SRB_STATUS_SUCCESS:
33121da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
33131da177e4SLinus Torvalds 		break;
33141da177e4SLinus Torvalds 	case SRB_STATUS_DATA_OVERRUN:
33151da177e4SLinus Torvalds 		switch (scsicmd->cmnd[0]) {
33161da177e4SLinus Torvalds 		case  READ_6:
33171da177e4SLinus Torvalds 		case  WRITE_6:
33181da177e4SLinus Torvalds 		case  READ_10:
33191da177e4SLinus Torvalds 		case  WRITE_10:
33201da177e4SLinus Torvalds 		case  READ_12:
33211da177e4SLinus Torvalds 		case  WRITE_12:
33227a8cf29dSMark Haverkamp 		case  READ_16:
33237a8cf29dSMark Haverkamp 		case  WRITE_16:
332455b87608SMahesh Rajashekhara 			if (le32_to_cpu(srbreply->data_xfer_length)
332555b87608SMahesh Rajashekhara 						< scsicmd->underflow)
33264ec57fb4SRaghava Aditya Renukunta 				pr_warn("aacraid: SCSI CMD underflow\n");
332755b87608SMahesh Rajashekhara 			else
33284ec57fb4SRaghava Aditya Renukunta 				pr_warn("aacraid: SCSI CMD Data Overrun\n");
332955b87608SMahesh Rajashekhara 			scsicmd->result = DID_ERROR << 16
333055b87608SMahesh Rajashekhara 					| COMMAND_COMPLETE << 8;
33311da177e4SLinus Torvalds 			break;
33324ec57fb4SRaghava Aditya Renukunta 		case INQUIRY:
333355b87608SMahesh Rajashekhara 			scsicmd->result = DID_OK << 16
333455b87608SMahesh Rajashekhara 					| COMMAND_COMPLETE << 8;
33351da177e4SLinus Torvalds 			break;
33361da177e4SLinus Torvalds 		default:
33371da177e4SLinus Torvalds 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
33381da177e4SLinus Torvalds 			break;
33391da177e4SLinus Torvalds 		}
33401da177e4SLinus Torvalds 		break;
33411da177e4SLinus Torvalds 	case SRB_STATUS_ABORTED:
33421da177e4SLinus Torvalds 		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
33431da177e4SLinus Torvalds 		break;
33441da177e4SLinus Torvalds 	case SRB_STATUS_ABORT_FAILED:
334555b87608SMahesh Rajashekhara 		/*
334655b87608SMahesh Rajashekhara 		 * Not sure about this one - but assuming the
334755b87608SMahesh Rajashekhara 		 * hba was trying to abort for some reason
334855b87608SMahesh Rajashekhara 		 */
33491da177e4SLinus Torvalds 		scsicmd->result = DID_ERROR << 16 | ABORT << 8;
33501da177e4SLinus Torvalds 		break;
33511da177e4SLinus Torvalds 	case SRB_STATUS_PARITY_ERROR:
335255b87608SMahesh Rajashekhara 		scsicmd->result = DID_PARITY << 16
335355b87608SMahesh Rajashekhara 				| MSG_PARITY_ERROR << 8;
33541da177e4SLinus Torvalds 		break;
33551da177e4SLinus Torvalds 	case SRB_STATUS_NO_DEVICE:
33561da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_PATH_ID:
33571da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_TARGET_ID:
33581da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_LUN:
33591da177e4SLinus Torvalds 	case SRB_STATUS_SELECTION_TIMEOUT:
336055b87608SMahesh Rajashekhara 		scsicmd->result = DID_NO_CONNECT << 16
336155b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
33621da177e4SLinus Torvalds 		break;
33631da177e4SLinus Torvalds 
33641da177e4SLinus Torvalds 	case SRB_STATUS_COMMAND_TIMEOUT:
33651da177e4SLinus Torvalds 	case SRB_STATUS_TIMEOUT:
336655b87608SMahesh Rajashekhara 		scsicmd->result = DID_TIME_OUT << 16
336755b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
33681da177e4SLinus Torvalds 		break;
33691da177e4SLinus Torvalds 
33701da177e4SLinus Torvalds 	case SRB_STATUS_BUSY:
337155b87608SMahesh Rajashekhara 		scsicmd->result = DID_BUS_BUSY << 16
337255b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
33731da177e4SLinus Torvalds 		break;
33741da177e4SLinus Torvalds 
33751da177e4SLinus Torvalds 	case SRB_STATUS_BUS_RESET:
337655b87608SMahesh Rajashekhara 		scsicmd->result = DID_RESET << 16
337755b87608SMahesh Rajashekhara 				| COMMAND_COMPLETE << 8;
33781da177e4SLinus Torvalds 		break;
33791da177e4SLinus Torvalds 
33801da177e4SLinus Torvalds 	case SRB_STATUS_MESSAGE_REJECTED:
338155b87608SMahesh Rajashekhara 		scsicmd->result = DID_ERROR << 16
338255b87608SMahesh Rajashekhara 				| MESSAGE_REJECT << 8;
33831da177e4SLinus Torvalds 		break;
33841da177e4SLinus Torvalds 	case SRB_STATUS_REQUEST_FLUSHED:
33851da177e4SLinus Torvalds 	case SRB_STATUS_ERROR:
33861da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_REQUEST:
33871da177e4SLinus Torvalds 	case SRB_STATUS_REQUEST_SENSE_FAILED:
33881da177e4SLinus Torvalds 	case SRB_STATUS_NO_HBA:
33891da177e4SLinus Torvalds 	case SRB_STATUS_UNEXPECTED_BUS_FREE:
33901da177e4SLinus Torvalds 	case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
33911da177e4SLinus Torvalds 	case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
33921da177e4SLinus Torvalds 	case SRB_STATUS_DELAYED_RETRY:
33931da177e4SLinus Torvalds 	case SRB_STATUS_BAD_FUNCTION:
33941da177e4SLinus Torvalds 	case SRB_STATUS_NOT_STARTED:
33951da177e4SLinus Torvalds 	case SRB_STATUS_NOT_IN_USE:
33961da177e4SLinus Torvalds 	case SRB_STATUS_FORCE_ABORT:
33971da177e4SLinus Torvalds 	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
33981da177e4SLinus Torvalds 	default:
33991da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
34004ec57fb4SRaghava Aditya Renukunta 		pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n",
34011da177e4SLinus Torvalds 			le32_to_cpu(srbreply->srb_status) & 0x3F,
34021da177e4SLinus Torvalds 			aac_get_status_string(
34031da177e4SLinus Torvalds 				le32_to_cpu(srbreply->srb_status) & 0x3F),
34041da177e4SLinus Torvalds 			scsicmd->cmnd[0],
34051da177e4SLinus Torvalds 			le32_to_cpu(srbreply->scsi_status));
34061da177e4SLinus Torvalds #endif
34074ec57fb4SRaghava Aditya Renukunta 		/*
34084ec57fb4SRaghava Aditya Renukunta 		 * When the CC bit is SET by the host in ATA pass thru CDB,
34094ec57fb4SRaghava Aditya Renukunta 		 *  driver is supposed to return DID_OK
34104ec57fb4SRaghava Aditya Renukunta 		 *
34114ec57fb4SRaghava Aditya Renukunta 		 * When the CC bit is RESET by the host, driver should
34124ec57fb4SRaghava Aditya Renukunta 		 *  return DID_ERROR
34134ec57fb4SRaghava Aditya Renukunta 		 */
34141fc8010aSRajashekhara, Mahesh 		if ((scsicmd->cmnd[0] == ATA_12)
34151fc8010aSRajashekhara, Mahesh 			|| (scsicmd->cmnd[0] == ATA_16)) {
34164ec57fb4SRaghava Aditya Renukunta 
34171fc8010aSRajashekhara, Mahesh 			if (scsicmd->cmnd[2] & (0x01 << 5)) {
34181fc8010aSRajashekhara, Mahesh 				scsicmd->result = DID_OK << 16
34191fc8010aSRajashekhara, Mahesh 					| COMMAND_COMPLETE << 8;
34201da177e4SLinus Torvalds 			break;
34211fc8010aSRajashekhara, Mahesh 			} else {
34221fc8010aSRajashekhara, Mahesh 				scsicmd->result = DID_ERROR << 16
34231fc8010aSRajashekhara, Mahesh 					| COMMAND_COMPLETE << 8;
34241fc8010aSRajashekhara, Mahesh 			break;
34251fc8010aSRajashekhara, Mahesh 			}
34261fc8010aSRajashekhara, Mahesh 		} else {
34271fc8010aSRajashekhara, Mahesh 			scsicmd->result = DID_ERROR << 16
34281fc8010aSRajashekhara, Mahesh 				| COMMAND_COMPLETE << 8;
34291fc8010aSRajashekhara, Mahesh 			break;
34301fc8010aSRajashekhara, Mahesh 		}
34311da177e4SLinus Torvalds 	}
343255b87608SMahesh Rajashekhara 	if (le32_to_cpu(srbreply->scsi_status)
343355b87608SMahesh Rajashekhara 			== SAM_STAT_CHECK_CONDITION) {
34341da177e4SLinus Torvalds 		int len;
343555b87608SMahesh Rajashekhara 
34361da177e4SLinus Torvalds 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
34373ace426fSSalyzyn, Mark 		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
34383ace426fSSalyzyn, Mark 			    SCSI_SENSE_BUFFERSIZE);
34391da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
34404ec57fb4SRaghava Aditya Renukunta 		pr_warn("aac_srb_callback: check condition, status = %d len=%d\n",
34417a8cf29dSMark Haverkamp 					le32_to_cpu(srbreply->status), len);
34421da177e4SLinus Torvalds #endif
344355b87608SMahesh Rajashekhara 		memcpy(scsicmd->sense_buffer,
344455b87608SMahesh Rajashekhara 				srbreply->sense_data, len);
344555b87608SMahesh Rajashekhara 	}
34464ec57fb4SRaghava Aditya Renukunta 
34471da177e4SLinus Torvalds 	/*
34481da177e4SLinus Torvalds 	 * OR in the scsi status (already shifted up a bit)
34491da177e4SLinus Torvalds 	 */
34501da177e4SLinus Torvalds 	scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
34511da177e4SLinus Torvalds 
3452bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
34538e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
34541da177e4SLinus Torvalds }
34551da177e4SLinus Torvalds 
3456ab5d129fSRaghava Aditya Renukunta static void hba_resp_task_complete(struct aac_dev *dev,
3457ab5d129fSRaghava Aditya Renukunta 					struct scsi_cmnd *scsicmd,
3458ab5d129fSRaghava Aditya Renukunta 					struct aac_hba_resp *err) {
3459ab5d129fSRaghava Aditya Renukunta 
3460ab5d129fSRaghava Aditya Renukunta 	scsicmd->result = err->status;
3461ab5d129fSRaghava Aditya Renukunta 	/* set residual count */
3462ab5d129fSRaghava Aditya Renukunta 	scsi_set_resid(scsicmd, le32_to_cpu(err->residual_count));
3463ab5d129fSRaghava Aditya Renukunta 
3464ab5d129fSRaghava Aditya Renukunta 	switch (err->status) {
3465ab5d129fSRaghava Aditya Renukunta 	case SAM_STAT_GOOD:
3466ab5d129fSRaghava Aditya Renukunta 		scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
3467ab5d129fSRaghava Aditya Renukunta 		break;
3468ab5d129fSRaghava Aditya Renukunta 	case SAM_STAT_CHECK_CONDITION:
3469ab5d129fSRaghava Aditya Renukunta 	{
3470ab5d129fSRaghava Aditya Renukunta 		int len;
3471ab5d129fSRaghava Aditya Renukunta 
3472ab5d129fSRaghava Aditya Renukunta 		len = min_t(u8, err->sense_response_data_len,
3473ab5d129fSRaghava Aditya Renukunta 			SCSI_SENSE_BUFFERSIZE);
3474ab5d129fSRaghava Aditya Renukunta 		if (len)
3475ab5d129fSRaghava Aditya Renukunta 			memcpy(scsicmd->sense_buffer,
3476ab5d129fSRaghava Aditya Renukunta 				err->sense_response_buf, len);
3477ab5d129fSRaghava Aditya Renukunta 		scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
3478ab5d129fSRaghava Aditya Renukunta 		break;
3479ab5d129fSRaghava Aditya Renukunta 	}
3480ab5d129fSRaghava Aditya Renukunta 	case SAM_STAT_BUSY:
3481ab5d129fSRaghava Aditya Renukunta 		scsicmd->result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
3482ab5d129fSRaghava Aditya Renukunta 		break;
3483ab5d129fSRaghava Aditya Renukunta 	case SAM_STAT_TASK_ABORTED:
3484ab5d129fSRaghava Aditya Renukunta 		scsicmd->result |= DID_ABORT << 16 | ABORT << 8;
3485ab5d129fSRaghava Aditya Renukunta 		break;
3486ab5d129fSRaghava Aditya Renukunta 	case SAM_STAT_RESERVATION_CONFLICT:
3487ab5d129fSRaghava Aditya Renukunta 	case SAM_STAT_TASK_SET_FULL:
3488ab5d129fSRaghava Aditya Renukunta 	default:
3489ab5d129fSRaghava Aditya Renukunta 		scsicmd->result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8;
3490ab5d129fSRaghava Aditya Renukunta 		break;
3491ab5d129fSRaghava Aditya Renukunta 	}
3492ab5d129fSRaghava Aditya Renukunta }
3493ab5d129fSRaghava Aditya Renukunta 
3494ab5d129fSRaghava Aditya Renukunta static void hba_resp_task_failure(struct aac_dev *dev,
3495ab5d129fSRaghava Aditya Renukunta 					struct scsi_cmnd *scsicmd,
3496ab5d129fSRaghava Aditya Renukunta 					struct aac_hba_resp *err)
3497ab5d129fSRaghava Aditya Renukunta {
3498ab5d129fSRaghava Aditya Renukunta 	switch (err->status) {
3499ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_HBAMODE_DISABLED:
3500ab5d129fSRaghava Aditya Renukunta 	{
3501ab5d129fSRaghava Aditya Renukunta 		u32 bus, cid;
3502ab5d129fSRaghava Aditya Renukunta 
3503ab5d129fSRaghava Aditya Renukunta 		bus = aac_logical_to_phys(scmd_channel(scsicmd));
3504ab5d129fSRaghava Aditya Renukunta 		cid = scmd_id(scsicmd);
3505ab5d129fSRaghava Aditya Renukunta 		if (dev->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) {
3506ab5d129fSRaghava Aditya Renukunta 			dev->hba_map[bus][cid].devtype = AAC_DEVTYPE_ARC_RAW;
3507ab5d129fSRaghava Aditya Renukunta 			dev->hba_map[bus][cid].rmw_nexus = 0xffffffff;
3508ab5d129fSRaghava Aditya Renukunta 		}
3509ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
3510ab5d129fSRaghava Aditya Renukunta 		break;
3511ab5d129fSRaghava Aditya Renukunta 	}
3512ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_IO_ERROR:
3513ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_NO_PATH_TO_DEVICE:
3514ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 |
3515ab5d129fSRaghava Aditya Renukunta 			COMMAND_COMPLETE << 8 | SAM_STAT_BUSY;
3516ab5d129fSRaghava Aditya Renukunta 		break;
3517ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_IO_ABORTED:
3518ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
3519ab5d129fSRaghava Aditya Renukunta 		break;
3520ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_INVALID_DEVICE:
3521ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
3522ab5d129fSRaghava Aditya Renukunta 		break;
3523ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_UNDERRUN:
3524ab5d129fSRaghava Aditya Renukunta 		/* UNDERRUN is OK */
3525ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
3526ab5d129fSRaghava Aditya Renukunta 		break;
3527ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_STAT_OVERRUN:
3528ab5d129fSRaghava Aditya Renukunta 	default:
3529ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
3530ab5d129fSRaghava Aditya Renukunta 		break;
3531ab5d129fSRaghava Aditya Renukunta 	}
3532ab5d129fSRaghava Aditya Renukunta }
3533ab5d129fSRaghava Aditya Renukunta 
35341da177e4SLinus Torvalds /**
35351da177e4SLinus Torvalds  *
3536ab5d129fSRaghava Aditya Renukunta  * aac_hba_callback
3537ab5d129fSRaghava Aditya Renukunta  * @context: the context set in the fib - here it is scsi cmd
3538ab5d129fSRaghava Aditya Renukunta  * @fibptr: pointer to the fib
3539ab5d129fSRaghava Aditya Renukunta  *
3540ab5d129fSRaghava Aditya Renukunta  * Handles the completion of a native HBA scsi command
3541ab5d129fSRaghava Aditya Renukunta  *
3542ab5d129fSRaghava Aditya Renukunta  */
3543ab5d129fSRaghava Aditya Renukunta void aac_hba_callback(void *context, struct fib *fibptr)
3544ab5d129fSRaghava Aditya Renukunta {
3545ab5d129fSRaghava Aditya Renukunta 	struct aac_dev *dev;
3546ab5d129fSRaghava Aditya Renukunta 	struct scsi_cmnd *scsicmd;
3547ab5d129fSRaghava Aditya Renukunta 
3548ab5d129fSRaghava Aditya Renukunta 	struct aac_hba_resp *err =
3549ab5d129fSRaghava Aditya Renukunta 			&((struct aac_native_hba *)fibptr->hw_fib_va)->resp.err;
3550ab5d129fSRaghava Aditya Renukunta 
3551ab5d129fSRaghava Aditya Renukunta 	scsicmd = (struct scsi_cmnd *) context;
3552ab5d129fSRaghava Aditya Renukunta 
3553ab5d129fSRaghava Aditya Renukunta 	if (!aac_valid_context(scsicmd, fibptr))
3554ab5d129fSRaghava Aditya Renukunta 		return;
3555ab5d129fSRaghava Aditya Renukunta 
3556ab5d129fSRaghava Aditya Renukunta 	WARN_ON(fibptr == NULL);
3557ab5d129fSRaghava Aditya Renukunta 	dev = fibptr->dev;
3558ab5d129fSRaghava Aditya Renukunta 
3559ab5d129fSRaghava Aditya Renukunta 	if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF))
3560ab5d129fSRaghava Aditya Renukunta 		scsi_dma_unmap(scsicmd);
3561ab5d129fSRaghava Aditya Renukunta 
3562ab5d129fSRaghava Aditya Renukunta 	if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
3563ab5d129fSRaghava Aditya Renukunta 		/* fast response */
3564ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
3565ab5d129fSRaghava Aditya Renukunta 		goto out;
3566ab5d129fSRaghava Aditya Renukunta 	}
3567ab5d129fSRaghava Aditya Renukunta 
3568ab5d129fSRaghava Aditya Renukunta 	switch (err->service_response) {
3569ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_SVCRES_TASK_COMPLETE:
3570ab5d129fSRaghava Aditya Renukunta 		hba_resp_task_complete(dev, scsicmd, err);
3571ab5d129fSRaghava Aditya Renukunta 		break;
3572ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_SVCRES_FAILURE:
3573ab5d129fSRaghava Aditya Renukunta 		hba_resp_task_failure(dev, scsicmd, err);
3574ab5d129fSRaghava Aditya Renukunta 		break;
3575ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_SVCRES_TMF_REJECTED:
3576ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
3577ab5d129fSRaghava Aditya Renukunta 		break;
3578ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_SVCRES_TMF_LUN_INVALID:
3579ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
3580ab5d129fSRaghava Aditya Renukunta 		break;
3581ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_SVCRES_TMF_COMPLETE:
3582ab5d129fSRaghava Aditya Renukunta 	case HBA_RESP_SVCRES_TMF_SUCCEEDED:
3583ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
3584ab5d129fSRaghava Aditya Renukunta 		break;
3585ab5d129fSRaghava Aditya Renukunta 	default:
3586ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
3587ab5d129fSRaghava Aditya Renukunta 		break;
3588ab5d129fSRaghava Aditya Renukunta 	}
3589ab5d129fSRaghava Aditya Renukunta 
3590ab5d129fSRaghava Aditya Renukunta out:
3591ab5d129fSRaghava Aditya Renukunta 	aac_fib_complete(fibptr);
3592ab5d129fSRaghava Aditya Renukunta 
3593ab5d129fSRaghava Aditya Renukunta 	if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF)
3594ab5d129fSRaghava Aditya Renukunta 		scsicmd->SCp.sent_command = 1;
3595ab5d129fSRaghava Aditya Renukunta 	else
3596ab5d129fSRaghava Aditya Renukunta 		scsicmd->scsi_done(scsicmd);
3597ab5d129fSRaghava Aditya Renukunta }
3598ab5d129fSRaghava Aditya Renukunta 
3599ab5d129fSRaghava Aditya Renukunta /**
3600ab5d129fSRaghava Aditya Renukunta  *
3601ab5d129fSRaghava Aditya Renukunta  * aac_send_srb_fib
36021da177e4SLinus Torvalds  * @scsicmd: the scsi command block
36031da177e4SLinus Torvalds  *
36041da177e4SLinus Torvalds  * This routine will form a FIB and fill in the aac_srb from the
36051da177e4SLinus Torvalds  * scsicmd passed in.
36061da177e4SLinus Torvalds  */
36071da177e4SLinus Torvalds 
36081da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
36091da177e4SLinus Torvalds {
36101da177e4SLinus Torvalds 	struct fib* cmd_fibcontext;
36111da177e4SLinus Torvalds 	struct aac_dev* dev;
36121da177e4SLinus Torvalds 	int status;
36131da177e4SLinus Torvalds 
361484971738SMark Haverkamp 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
3615e5718774SMark Haverkamp 	if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
361684971738SMark Haverkamp 			scsicmd->device->lun > 7) {
36171da177e4SLinus Torvalds 		scsicmd->result = DID_NO_CONNECT << 16;
36181da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
36191da177e4SLinus Torvalds 		return 0;
36201da177e4SLinus Torvalds 	}
36211da177e4SLinus Torvalds 
36221da177e4SLinus Torvalds 	/*
36231da177e4SLinus Torvalds 	 *	Allocate and initialize a Fib then setup a BlockWrite command
36241da177e4SLinus Torvalds 	 */
36256bf3b630SRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
36266bf3b630SRaghava Aditya Renukunta 
3627e8f32de5SMark Haverkamp 	status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
36281da177e4SLinus Torvalds 
36291da177e4SLinus Torvalds 	/*
36301da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
36311da177e4SLinus Torvalds 	 */
36321da177e4SLinus Torvalds 	if (status == -EINPROGRESS) {
363377d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
36341da177e4SLinus Torvalds 		return 0;
36351da177e4SLinus Torvalds 	}
36361da177e4SLinus Torvalds 
3637bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
3638bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
3639bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
36401da177e4SLinus Torvalds 
36411da177e4SLinus Torvalds 	return -1;
36421da177e4SLinus Torvalds }
36431da177e4SLinus Torvalds 
3644ab5d129fSRaghava Aditya Renukunta /**
3645ab5d129fSRaghava Aditya Renukunta  *
3646ab5d129fSRaghava Aditya Renukunta  * aac_send_hba_fib
3647ab5d129fSRaghava Aditya Renukunta  * @scsicmd: the scsi command block
3648ab5d129fSRaghava Aditya Renukunta  *
3649ab5d129fSRaghava Aditya Renukunta  * This routine will form a FIB and fill in the aac_hba_cmd_req from the
3650ab5d129fSRaghava Aditya Renukunta  * scsicmd passed in.
3651ab5d129fSRaghava Aditya Renukunta  */
3652ab5d129fSRaghava Aditya Renukunta static int aac_send_hba_fib(struct scsi_cmnd *scsicmd)
3653ab5d129fSRaghava Aditya Renukunta {
3654ab5d129fSRaghava Aditya Renukunta 	struct fib *cmd_fibcontext;
3655ab5d129fSRaghava Aditya Renukunta 	struct aac_dev *dev;
3656ab5d129fSRaghava Aditya Renukunta 	int status;
3657ab5d129fSRaghava Aditya Renukunta 
3658ab5d129fSRaghava Aditya Renukunta 	dev = shost_priv(scsicmd->device->host);
3659ab5d129fSRaghava Aditya Renukunta 	if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
3660ab5d129fSRaghava Aditya Renukunta 			scsicmd->device->lun > AAC_MAX_LUN - 1) {
3661ab5d129fSRaghava Aditya Renukunta 		scsicmd->result = DID_NO_CONNECT << 16;
3662ab5d129fSRaghava Aditya Renukunta 		scsicmd->scsi_done(scsicmd);
3663ab5d129fSRaghava Aditya Renukunta 		return 0;
3664ab5d129fSRaghava Aditya Renukunta 	}
3665ab5d129fSRaghava Aditya Renukunta 
3666ab5d129fSRaghava Aditya Renukunta 	/*
3667ab5d129fSRaghava Aditya Renukunta 	 *	Allocate and initialize a Fib then setup a BlockWrite command
3668ab5d129fSRaghava Aditya Renukunta 	 */
3669ab5d129fSRaghava Aditya Renukunta 	cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
3670ab5d129fSRaghava Aditya Renukunta 	if (!cmd_fibcontext)
3671ab5d129fSRaghava Aditya Renukunta 		return -1;
3672ab5d129fSRaghava Aditya Renukunta 
3673ab5d129fSRaghava Aditya Renukunta 	status = aac_adapter_hba(cmd_fibcontext, scsicmd);
3674ab5d129fSRaghava Aditya Renukunta 
3675ab5d129fSRaghava Aditya Renukunta 	/*
3676ab5d129fSRaghava Aditya Renukunta 	 *	Check that the command queued to the controller
3677ab5d129fSRaghava Aditya Renukunta 	 */
3678ab5d129fSRaghava Aditya Renukunta 	if (status == -EINPROGRESS) {
3679ab5d129fSRaghava Aditya Renukunta 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
3680ab5d129fSRaghava Aditya Renukunta 		return 0;
3681ab5d129fSRaghava Aditya Renukunta 	}
3682ab5d129fSRaghava Aditya Renukunta 
3683ab5d129fSRaghava Aditya Renukunta 	pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n",
3684ab5d129fSRaghava Aditya Renukunta 		status);
3685ab5d129fSRaghava Aditya Renukunta 	aac_fib_complete(cmd_fibcontext);
3686ab5d129fSRaghava Aditya Renukunta 	aac_fib_free(cmd_fibcontext);
3687ab5d129fSRaghava Aditya Renukunta 
3688ab5d129fSRaghava Aditya Renukunta 	return -1;
3689ab5d129fSRaghava Aditya Renukunta }
3690ab5d129fSRaghava Aditya Renukunta 
3691ab5d129fSRaghava Aditya Renukunta 
36920b433447SMahesh Rajashekhara static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
36931da177e4SLinus Torvalds {
36941da177e4SLinus Torvalds 	struct aac_dev *dev;
36951da177e4SLinus Torvalds 	unsigned long byte_count = 0;
3696727eead6SFUJITA Tomonori 	int nseg;
36971da177e4SLinus Torvalds 
36981da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
36991da177e4SLinus Torvalds 	// Get rid of old data
37001da177e4SLinus Torvalds 	psg->count = 0;
37011da177e4SLinus Torvalds 	psg->sg[0].addr = 0;
37021da177e4SLinus Torvalds 	psg->sg[0].count = 0;
3703727eead6SFUJITA Tomonori 
3704727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
37050b433447SMahesh Rajashekhara 	if (nseg < 0)
37060b433447SMahesh Rajashekhara 		return nseg;
3707727eead6SFUJITA Tomonori 	if (nseg) {
37081da177e4SLinus Torvalds 		struct scatterlist *sg;
37091da177e4SLinus Torvalds 		int i;
37101da177e4SLinus Torvalds 
3711727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
37121da177e4SLinus Torvalds 
3713727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
37141da177e4SLinus Torvalds 			psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
37151da177e4SLinus Torvalds 			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
37161da177e4SLinus Torvalds 			byte_count += sg_dma_len(sg);
37171da177e4SLinus Torvalds 		}
37181da177e4SLinus Torvalds 		/* hba wants the size to be exact */
3719727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
372056b58712SMark Haverkamp  			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
3721727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
372256b58712SMark Haverkamp  			psg->sg[i-1].count = cpu_to_le32(temp);
3723727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
37241da177e4SLinus Torvalds 		}
37251da177e4SLinus Torvalds 		/* Check for command underflow */
37261da177e4SLinus Torvalds 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
37271da177e4SLinus Torvalds 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
37281da177e4SLinus Torvalds 					byte_count, scsicmd->underflow);
37291da177e4SLinus Torvalds 		}
37301da177e4SLinus Torvalds 	}
37311da177e4SLinus Torvalds 	return byte_count;
37321da177e4SLinus Torvalds }
37331da177e4SLinus Torvalds 
37341da177e4SLinus Torvalds 
37350b433447SMahesh Rajashekhara static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg)
37361da177e4SLinus Torvalds {
37371da177e4SLinus Torvalds 	struct aac_dev *dev;
37381da177e4SLinus Torvalds 	unsigned long byte_count = 0;
373956b58712SMark Haverkamp  	u64 addr;
3740727eead6SFUJITA Tomonori 	int nseg;
37411da177e4SLinus Torvalds 
37421da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
37431da177e4SLinus Torvalds 	// Get rid of old data
37441da177e4SLinus Torvalds 	psg->count = 0;
37451da177e4SLinus Torvalds 	psg->sg[0].addr[0] = 0;
37461da177e4SLinus Torvalds 	psg->sg[0].addr[1] = 0;
37471da177e4SLinus Torvalds 	psg->sg[0].count = 0;
3748727eead6SFUJITA Tomonori 
3749727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
37500b433447SMahesh Rajashekhara 	if (nseg < 0)
37510b433447SMahesh Rajashekhara 		return nseg;
3752727eead6SFUJITA Tomonori 	if (nseg) {
37531da177e4SLinus Torvalds 		struct scatterlist *sg;
37541da177e4SLinus Torvalds 		int i;
37551da177e4SLinus Torvalds 
3756727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
37571241f359SMark Haverkamp 			int count = sg_dma_len(sg);
375856b58712SMark Haverkamp  			addr = sg_dma_address(sg);
375956b58712SMark Haverkamp  			psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
376056b58712SMark Haverkamp  			psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
37611241f359SMark Haverkamp 			psg->sg[i].count = cpu_to_le32(count);
37621241f359SMark Haverkamp 			byte_count += count;
37631da177e4SLinus Torvalds 		}
3764727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
37651da177e4SLinus Torvalds 		/* hba wants the size to be exact */
3766727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
376756b58712SMark Haverkamp  			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
3768727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
376956b58712SMark Haverkamp  			psg->sg[i-1].count = cpu_to_le32(temp);
3770727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
37711da177e4SLinus Torvalds 		}
37721da177e4SLinus Torvalds 		/* Check for command underflow */
37731da177e4SLinus Torvalds 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
37741da177e4SLinus Torvalds 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
37751da177e4SLinus Torvalds 					byte_count, scsicmd->underflow);
37761da177e4SLinus Torvalds 		}
37771da177e4SLinus Torvalds 	}
37781da177e4SLinus Torvalds 	return byte_count;
37791da177e4SLinus Torvalds }
37801da177e4SLinus Torvalds 
37810b433447SMahesh Rajashekhara static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg)
37820e68c003SMark Haverkamp {
37830e68c003SMark Haverkamp 	unsigned long byte_count = 0;
3784727eead6SFUJITA Tomonori 	int nseg;
37850e68c003SMark Haverkamp 
37860e68c003SMark Haverkamp 	// Get rid of old data
37870e68c003SMark Haverkamp 	psg->count = 0;
37880e68c003SMark Haverkamp 	psg->sg[0].next = 0;
37890e68c003SMark Haverkamp 	psg->sg[0].prev = 0;
37900e68c003SMark Haverkamp 	psg->sg[0].addr[0] = 0;
37910e68c003SMark Haverkamp 	psg->sg[0].addr[1] = 0;
37920e68c003SMark Haverkamp 	psg->sg[0].count = 0;
37930e68c003SMark Haverkamp 	psg->sg[0].flags = 0;
3794727eead6SFUJITA Tomonori 
3795727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
37960b433447SMahesh Rajashekhara 	if (nseg < 0)
37970b433447SMahesh Rajashekhara 		return nseg;
3798727eead6SFUJITA Tomonori 	if (nseg) {
37990e68c003SMark Haverkamp 		struct scatterlist *sg;
38000e68c003SMark Haverkamp 		int i;
38010e68c003SMark Haverkamp 
3802727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
38030e68c003SMark Haverkamp 			int count = sg_dma_len(sg);
38040e68c003SMark Haverkamp 			u64 addr = sg_dma_address(sg);
38050e68c003SMark Haverkamp 			psg->sg[i].next = 0;
38060e68c003SMark Haverkamp 			psg->sg[i].prev = 0;
38070e68c003SMark Haverkamp 			psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
38080e68c003SMark Haverkamp 			psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
38090e68c003SMark Haverkamp 			psg->sg[i].count = cpu_to_le32(count);
38100e68c003SMark Haverkamp 			psg->sg[i].flags = 0;
38110e68c003SMark Haverkamp 			byte_count += count;
38120e68c003SMark Haverkamp 		}
3813727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
38140e68c003SMark Haverkamp 		/* hba wants the size to be exact */
3815727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
38160e68c003SMark Haverkamp 			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
3817727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
38180e68c003SMark Haverkamp 			psg->sg[i-1].count = cpu_to_le32(temp);
3819727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
38200e68c003SMark Haverkamp 		}
38210e68c003SMark Haverkamp 		/* Check for command underflow */
38220e68c003SMark Haverkamp 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
38230e68c003SMark Haverkamp 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
38240e68c003SMark Haverkamp 					byte_count, scsicmd->underflow);
38250e68c003SMark Haverkamp 		}
38260e68c003SMark Haverkamp 	}
38270e68c003SMark Haverkamp 	return byte_count;
38280e68c003SMark Haverkamp }
38290e68c003SMark Haverkamp 
38300b433447SMahesh Rajashekhara static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
38310b433447SMahesh Rajashekhara 				struct aac_raw_io2 *rio2, int sg_max)
383285d22bbfSMahesh Rajashekhara {
383385d22bbfSMahesh Rajashekhara 	unsigned long byte_count = 0;
383485d22bbfSMahesh Rajashekhara 	int nseg;
383585d22bbfSMahesh Rajashekhara 
383685d22bbfSMahesh Rajashekhara 	nseg = scsi_dma_map(scsicmd);
38370b433447SMahesh Rajashekhara 	if (nseg < 0)
38380b433447SMahesh Rajashekhara 		return nseg;
383985d22bbfSMahesh Rajashekhara 	if (nseg) {
384085d22bbfSMahesh Rajashekhara 		struct scatterlist *sg;
384185d22bbfSMahesh Rajashekhara 		int i, conformable = 0;
384285d22bbfSMahesh Rajashekhara 		u32 min_size = PAGE_SIZE, cur_size;
384385d22bbfSMahesh Rajashekhara 
384485d22bbfSMahesh Rajashekhara 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
384585d22bbfSMahesh Rajashekhara 			int count = sg_dma_len(sg);
384685d22bbfSMahesh Rajashekhara 			u64 addr = sg_dma_address(sg);
384785d22bbfSMahesh Rajashekhara 
384885d22bbfSMahesh Rajashekhara 			BUG_ON(i >= sg_max);
384985d22bbfSMahesh Rajashekhara 			rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32));
385085d22bbfSMahesh Rajashekhara 			rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff));
385185d22bbfSMahesh Rajashekhara 			cur_size = cpu_to_le32(count);
385285d22bbfSMahesh Rajashekhara 			rio2->sge[i].length = cur_size;
385385d22bbfSMahesh Rajashekhara 			rio2->sge[i].flags = 0;
385485d22bbfSMahesh Rajashekhara 			if (i == 0) {
385585d22bbfSMahesh Rajashekhara 				conformable = 1;
385685d22bbfSMahesh Rajashekhara 				rio2->sgeFirstSize = cur_size;
385785d22bbfSMahesh Rajashekhara 			} else if (i == 1) {
385885d22bbfSMahesh Rajashekhara 				rio2->sgeNominalSize = cur_size;
385985d22bbfSMahesh Rajashekhara 				min_size = cur_size;
386085d22bbfSMahesh Rajashekhara 			} else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) {
386185d22bbfSMahesh Rajashekhara 				conformable = 0;
386285d22bbfSMahesh Rajashekhara 				if (cur_size < min_size)
386385d22bbfSMahesh Rajashekhara 					min_size = cur_size;
386485d22bbfSMahesh Rajashekhara 			}
386585d22bbfSMahesh Rajashekhara 			byte_count += count;
386685d22bbfSMahesh Rajashekhara 		}
386785d22bbfSMahesh Rajashekhara 
386885d22bbfSMahesh Rajashekhara 		/* hba wants the size to be exact */
386985d22bbfSMahesh Rajashekhara 		if (byte_count > scsi_bufflen(scsicmd)) {
387085d22bbfSMahesh Rajashekhara 			u32 temp = le32_to_cpu(rio2->sge[i-1].length) -
387185d22bbfSMahesh Rajashekhara 				(byte_count - scsi_bufflen(scsicmd));
387285d22bbfSMahesh Rajashekhara 			rio2->sge[i-1].length = cpu_to_le32(temp);
387385d22bbfSMahesh Rajashekhara 			byte_count = scsi_bufflen(scsicmd);
387485d22bbfSMahesh Rajashekhara 		}
387585d22bbfSMahesh Rajashekhara 
387685d22bbfSMahesh Rajashekhara 		rio2->sgeCnt = cpu_to_le32(nseg);
387785d22bbfSMahesh Rajashekhara 		rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212);
387885d22bbfSMahesh Rajashekhara 		/* not conformable: evaluate required sg elements */
387985d22bbfSMahesh Rajashekhara 		if (!conformable) {
388085d22bbfSMahesh Rajashekhara 			int j, nseg_new = nseg, err_found;
388185d22bbfSMahesh Rajashekhara 			for (i = min_size / PAGE_SIZE; i >= 1; --i) {
388285d22bbfSMahesh Rajashekhara 				err_found = 0;
388385d22bbfSMahesh Rajashekhara 				nseg_new = 2;
388485d22bbfSMahesh Rajashekhara 				for (j = 1; j < nseg - 1; ++j) {
388585d22bbfSMahesh Rajashekhara 					if (rio2->sge[j].length % (i*PAGE_SIZE)) {
388685d22bbfSMahesh Rajashekhara 						err_found = 1;
388785d22bbfSMahesh Rajashekhara 						break;
388885d22bbfSMahesh Rajashekhara 					}
388985d22bbfSMahesh Rajashekhara 					nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE));
389085d22bbfSMahesh Rajashekhara 				}
389185d22bbfSMahesh Rajashekhara 				if (!err_found)
389285d22bbfSMahesh Rajashekhara 					break;
389385d22bbfSMahesh Rajashekhara 			}
389485d22bbfSMahesh Rajashekhara 			if (i > 0 && nseg_new <= sg_max)
389585d22bbfSMahesh Rajashekhara 				aac_convert_sgraw2(rio2, i, nseg, nseg_new);
389685d22bbfSMahesh Rajashekhara 		} else
389785d22bbfSMahesh Rajashekhara 			rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT);
389885d22bbfSMahesh Rajashekhara 
389985d22bbfSMahesh Rajashekhara 		/* Check for command underflow */
390085d22bbfSMahesh Rajashekhara 		if (scsicmd->underflow && (byte_count < scsicmd->underflow)) {
390185d22bbfSMahesh Rajashekhara 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
390285d22bbfSMahesh Rajashekhara 					byte_count, scsicmd->underflow);
390385d22bbfSMahesh Rajashekhara 		}
390485d22bbfSMahesh Rajashekhara 	}
390585d22bbfSMahesh Rajashekhara 
390685d22bbfSMahesh Rajashekhara 	return byte_count;
390785d22bbfSMahesh Rajashekhara }
390885d22bbfSMahesh Rajashekhara 
390985d22bbfSMahesh Rajashekhara static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new)
391085d22bbfSMahesh Rajashekhara {
391185d22bbfSMahesh Rajashekhara 	struct sge_ieee1212 *sge;
391285d22bbfSMahesh Rajashekhara 	int i, j, pos;
391385d22bbfSMahesh Rajashekhara 	u32 addr_low;
391485d22bbfSMahesh Rajashekhara 
391585d22bbfSMahesh Rajashekhara 	if (aac_convert_sgl == 0)
391685d22bbfSMahesh Rajashekhara 		return 0;
391785d22bbfSMahesh Rajashekhara 
391885d22bbfSMahesh Rajashekhara 	sge = kmalloc(nseg_new * sizeof(struct sge_ieee1212), GFP_ATOMIC);
391985d22bbfSMahesh Rajashekhara 	if (sge == NULL)
392085d22bbfSMahesh Rajashekhara 		return -1;
392185d22bbfSMahesh Rajashekhara 
392285d22bbfSMahesh Rajashekhara 	for (i = 1, pos = 1; i < nseg-1; ++i) {
392385d22bbfSMahesh Rajashekhara 		for (j = 0; j < rio2->sge[i].length / (pages * PAGE_SIZE); ++j) {
392485d22bbfSMahesh Rajashekhara 			addr_low = rio2->sge[i].addrLow + j * pages * PAGE_SIZE;
392585d22bbfSMahesh Rajashekhara 			sge[pos].addrLow = addr_low;
392685d22bbfSMahesh Rajashekhara 			sge[pos].addrHigh = rio2->sge[i].addrHigh;
392785d22bbfSMahesh Rajashekhara 			if (addr_low < rio2->sge[i].addrLow)
392885d22bbfSMahesh Rajashekhara 				sge[pos].addrHigh++;
392985d22bbfSMahesh Rajashekhara 			sge[pos].length = pages * PAGE_SIZE;
393085d22bbfSMahesh Rajashekhara 			sge[pos].flags = 0;
393185d22bbfSMahesh Rajashekhara 			pos++;
393285d22bbfSMahesh Rajashekhara 		}
393385d22bbfSMahesh Rajashekhara 	}
393485d22bbfSMahesh Rajashekhara 	sge[pos] = rio2->sge[nseg-1];
393585d22bbfSMahesh Rajashekhara 	memcpy(&rio2->sge[1], &sge[1], (nseg_new-1)*sizeof(struct sge_ieee1212));
393685d22bbfSMahesh Rajashekhara 
393785d22bbfSMahesh Rajashekhara 	kfree(sge);
393885d22bbfSMahesh Rajashekhara 	rio2->sgeCnt = cpu_to_le32(nseg_new);
393985d22bbfSMahesh Rajashekhara 	rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT);
394085d22bbfSMahesh Rajashekhara 	rio2->sgeNominalSize = pages * PAGE_SIZE;
394185d22bbfSMahesh Rajashekhara 	return 0;
394285d22bbfSMahesh Rajashekhara }
394385d22bbfSMahesh Rajashekhara 
3944ab5d129fSRaghava Aditya Renukunta static long aac_build_sghba(struct scsi_cmnd *scsicmd,
3945ab5d129fSRaghava Aditya Renukunta 			struct aac_hba_cmd_req *hbacmd,
3946ab5d129fSRaghava Aditya Renukunta 			int sg_max,
3947ab5d129fSRaghava Aditya Renukunta 			u64 sg_address)
3948ab5d129fSRaghava Aditya Renukunta {
3949ab5d129fSRaghava Aditya Renukunta 	unsigned long byte_count = 0;
3950ab5d129fSRaghava Aditya Renukunta 	int nseg;
3951ab5d129fSRaghava Aditya Renukunta 	struct scatterlist *sg;
3952ab5d129fSRaghava Aditya Renukunta 	int i;
3953ab5d129fSRaghava Aditya Renukunta 	u32 cur_size;
3954ab5d129fSRaghava Aditya Renukunta 	struct aac_hba_sgl *sge;
3955ab5d129fSRaghava Aditya Renukunta 
3956ab5d129fSRaghava Aditya Renukunta 
3957ab5d129fSRaghava Aditya Renukunta 
3958ab5d129fSRaghava Aditya Renukunta 	nseg = scsi_dma_map(scsicmd);
3959ab5d129fSRaghava Aditya Renukunta 	if (nseg <= 0) {
3960ab5d129fSRaghava Aditya Renukunta 		byte_count = nseg;
3961ab5d129fSRaghava Aditya Renukunta 		goto out;
3962ab5d129fSRaghava Aditya Renukunta 	}
3963ab5d129fSRaghava Aditya Renukunta 
3964ab5d129fSRaghava Aditya Renukunta 	if (nseg > HBA_MAX_SG_EMBEDDED)
3965ab5d129fSRaghava Aditya Renukunta 		sge = &hbacmd->sge[2];
3966ab5d129fSRaghava Aditya Renukunta 	else
3967ab5d129fSRaghava Aditya Renukunta 		sge = &hbacmd->sge[0];
3968ab5d129fSRaghava Aditya Renukunta 
3969ab5d129fSRaghava Aditya Renukunta 	scsi_for_each_sg(scsicmd, sg, nseg, i) {
3970ab5d129fSRaghava Aditya Renukunta 		int count = sg_dma_len(sg);
3971ab5d129fSRaghava Aditya Renukunta 		u64 addr = sg_dma_address(sg);
3972ab5d129fSRaghava Aditya Renukunta 
3973ab5d129fSRaghava Aditya Renukunta 		WARN_ON(i >= sg_max);
3974ab5d129fSRaghava Aditya Renukunta 		sge->addr_hi = cpu_to_le32((u32)(addr>>32));
3975ab5d129fSRaghava Aditya Renukunta 		sge->addr_lo = cpu_to_le32((u32)(addr & 0xffffffff));
3976ab5d129fSRaghava Aditya Renukunta 		cur_size = cpu_to_le32(count);
3977ab5d129fSRaghava Aditya Renukunta 		sge->len = cur_size;
3978ab5d129fSRaghava Aditya Renukunta 		sge->flags = 0;
3979ab5d129fSRaghava Aditya Renukunta 		byte_count += count;
3980ab5d129fSRaghava Aditya Renukunta 		sge++;
3981ab5d129fSRaghava Aditya Renukunta 	}
3982ab5d129fSRaghava Aditya Renukunta 
3983ab5d129fSRaghava Aditya Renukunta 	sge--;
3984ab5d129fSRaghava Aditya Renukunta 	/* hba wants the size to be exact */
3985ab5d129fSRaghava Aditya Renukunta 	if (byte_count > scsi_bufflen(scsicmd)) {
3986ab5d129fSRaghava Aditya Renukunta 		u32 temp;
3987ab5d129fSRaghava Aditya Renukunta 
3988ab5d129fSRaghava Aditya Renukunta 		temp = le32_to_cpu(sge->len) - byte_count
3989ab5d129fSRaghava Aditya Renukunta 						- scsi_bufflen(scsicmd);
3990ab5d129fSRaghava Aditya Renukunta 		sge->len = cpu_to_le32(temp);
3991ab5d129fSRaghava Aditya Renukunta 		byte_count = scsi_bufflen(scsicmd);
3992ab5d129fSRaghava Aditya Renukunta 	}
3993ab5d129fSRaghava Aditya Renukunta 
3994ab5d129fSRaghava Aditya Renukunta 	if (nseg <= HBA_MAX_SG_EMBEDDED) {
3995ab5d129fSRaghava Aditya Renukunta 		hbacmd->emb_data_desc_count = cpu_to_le32(nseg);
3996ab5d129fSRaghava Aditya Renukunta 		sge->flags = cpu_to_le32(0x40000000);
3997ab5d129fSRaghava Aditya Renukunta 	} else {
3998ab5d129fSRaghava Aditya Renukunta 		/* not embedded */
3999ab5d129fSRaghava Aditya Renukunta 		hbacmd->sge[0].flags = cpu_to_le32(0x80000000);
4000ab5d129fSRaghava Aditya Renukunta 		hbacmd->emb_data_desc_count = (u8)cpu_to_le32(1);
4001ab5d129fSRaghava Aditya Renukunta 		hbacmd->sge[0].addr_hi = (u32)cpu_to_le32(sg_address >> 32);
4002ab5d129fSRaghava Aditya Renukunta 		hbacmd->sge[0].addr_lo =
4003ab5d129fSRaghava Aditya Renukunta 			cpu_to_le32((u32)(sg_address & 0xffffffff));
4004ab5d129fSRaghava Aditya Renukunta 	}
4005ab5d129fSRaghava Aditya Renukunta 
4006ab5d129fSRaghava Aditya Renukunta 	/* Check for command underflow */
4007ab5d129fSRaghava Aditya Renukunta 	if (scsicmd->underflow && (byte_count < scsicmd->underflow)) {
4008ab5d129fSRaghava Aditya Renukunta 		pr_warn("aacraid: cmd len %08lX cmd underflow %08X\n",
4009ab5d129fSRaghava Aditya Renukunta 				byte_count, scsicmd->underflow);
4010ab5d129fSRaghava Aditya Renukunta 	}
4011ab5d129fSRaghava Aditya Renukunta out:
4012ab5d129fSRaghava Aditya Renukunta 	return byte_count;
4013ab5d129fSRaghava Aditya Renukunta }
4014ab5d129fSRaghava Aditya Renukunta 
40151da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
40161da177e4SLinus Torvalds 
40171da177e4SLinus Torvalds struct aac_srb_status_info {
40181da177e4SLinus Torvalds 	u32	status;
40191da177e4SLinus Torvalds 	char	*str;
40201da177e4SLinus Torvalds };
40211da177e4SLinus Torvalds 
40221da177e4SLinus Torvalds 
40231da177e4SLinus Torvalds static struct aac_srb_status_info srb_status_info[] = {
40241da177e4SLinus Torvalds 	{ SRB_STATUS_PENDING,		"Pending Status"},
40251da177e4SLinus Torvalds 	{ SRB_STATUS_SUCCESS,		"Success"},
40261da177e4SLinus Torvalds 	{ SRB_STATUS_ABORTED,		"Aborted Command"},
40271da177e4SLinus Torvalds 	{ SRB_STATUS_ABORT_FAILED,	"Abort Failed"},
40281da177e4SLinus Torvalds 	{ SRB_STATUS_ERROR,		"Error Event"},
40291da177e4SLinus Torvalds 	{ SRB_STATUS_BUSY,		"Device Busy"},
40301da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_REQUEST,	"Invalid Request"},
40311da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_PATH_ID,	"Invalid Path ID"},
40321da177e4SLinus Torvalds 	{ SRB_STATUS_NO_DEVICE,		"No Device"},
40331da177e4SLinus Torvalds 	{ SRB_STATUS_TIMEOUT,		"Timeout"},
40341da177e4SLinus Torvalds 	{ SRB_STATUS_SELECTION_TIMEOUT,	"Selection Timeout"},
40351da177e4SLinus Torvalds 	{ SRB_STATUS_COMMAND_TIMEOUT,	"Command Timeout"},
40361da177e4SLinus Torvalds 	{ SRB_STATUS_MESSAGE_REJECTED,	"Message Rejected"},
40371da177e4SLinus Torvalds 	{ SRB_STATUS_BUS_RESET,		"Bus Reset"},
40381da177e4SLinus Torvalds 	{ SRB_STATUS_PARITY_ERROR,	"Parity Error"},
40391da177e4SLinus Torvalds 	{ SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"},
40401da177e4SLinus Torvalds 	{ SRB_STATUS_NO_HBA,		"No HBA"},
40411da177e4SLinus Torvalds 	{ SRB_STATUS_DATA_OVERRUN,	"Data Overrun/Data Underrun"},
40421da177e4SLinus Torvalds 	{ SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"},
40431da177e4SLinus Torvalds 	{ SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"},
40441da177e4SLinus Torvalds 	{ SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
40451da177e4SLinus Torvalds 	{ SRB_STATUS_REQUEST_FLUSHED,	"Request Flushed"},
40461da177e4SLinus Torvalds 	{ SRB_STATUS_DELAYED_RETRY,	"Delayed Retry"},
40471da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_LUN,	"Invalid LUN"},
40481da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_TARGET_ID,	"Invalid TARGET ID"},
40491da177e4SLinus Torvalds 	{ SRB_STATUS_BAD_FUNCTION,	"Bad Function"},
40501da177e4SLinus Torvalds 	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
40511da177e4SLinus Torvalds 	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
40521da177e4SLinus Torvalds 	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
40531da177e4SLinus Torvalds 	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
40541da177e4SLinus Torvalds 	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
40551da177e4SLinus Torvalds 	{ 0xff,				"Unknown Error"}
40561da177e4SLinus Torvalds };
40571da177e4SLinus Torvalds 
40581da177e4SLinus Torvalds char *aac_get_status_string(u32 status)
40591da177e4SLinus Torvalds {
40601da177e4SLinus Torvalds 	int i;
40611da177e4SLinus Torvalds 
40626391a113STobias Klauser 	for (i = 0; i < ARRAY_SIZE(srb_status_info); i++)
40636391a113STobias Klauser 		if (srb_status_info[i].status == status)
40641da177e4SLinus Torvalds 			return srb_status_info[i].str;
40651da177e4SLinus Torvalds 
40661da177e4SLinus Torvalds 	return "Bad Status Code";
40671da177e4SLinus Torvalds }
40681da177e4SLinus Torvalds 
40691da177e4SLinus Torvalds #endif
4070