xref: /openbmc/linux/drivers/scsi/aacraid/aachba.c (revision acf3368f)
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>
351da177e4SLinus Torvalds #include <asm/uaccess.h>
363a0086a8SSalyzyn, Mark #include <linux/highmem.h> /* For flush_kernel_dcache_page */
37acf3368fSPaul Gortmaker #include <linux/module.h>
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #include <scsi/scsi.h>
401da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
411da177e4SLinus Torvalds #include <scsi/scsi_device.h>
421da177e4SLinus Torvalds #include <scsi/scsi_host.h>
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds #include "aacraid.h"
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds /* values for inqd_pdt: Peripheral device type in plain English */
471da177e4SLinus Torvalds #define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
481da177e4SLinus Torvalds #define	INQD_PDT_PROC	0x03	/* Processor device */
491da177e4SLinus Torvalds #define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
501da177e4SLinus Torvalds #define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
511da177e4SLinus Torvalds #define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
521da177e4SLinus Torvalds #define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
551da177e4SLinus Torvalds #define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds /*
581da177e4SLinus Torvalds  *	Sense codes
591da177e4SLinus Torvalds  */
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds #define SENCODE_NO_SENSE			0x00
621da177e4SLinus Torvalds #define SENCODE_END_OF_DATA			0x00
631da177e4SLinus Torvalds #define SENCODE_BECOMING_READY			0x04
641da177e4SLinus Torvalds #define SENCODE_INIT_CMD_REQUIRED		0x04
651da177e4SLinus Torvalds #define SENCODE_PARAM_LIST_LENGTH_ERROR		0x1A
661da177e4SLinus Torvalds #define SENCODE_INVALID_COMMAND			0x20
671da177e4SLinus Torvalds #define SENCODE_LBA_OUT_OF_RANGE		0x21
681da177e4SLinus Torvalds #define SENCODE_INVALID_CDB_FIELD		0x24
691da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SUPPORTED		0x25
701da177e4SLinus Torvalds #define SENCODE_INVALID_PARAM_FIELD		0x26
711da177e4SLinus Torvalds #define SENCODE_PARAM_NOT_SUPPORTED		0x26
721da177e4SLinus Torvalds #define SENCODE_PARAM_VALUE_INVALID		0x26
731da177e4SLinus Torvalds #define SENCODE_RESET_OCCURRED			0x29
741da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x3E
751da177e4SLinus Torvalds #define SENCODE_INQUIRY_DATA_CHANGED		0x3F
761da177e4SLinus Torvalds #define SENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x39
771da177e4SLinus Torvalds #define SENCODE_DIAGNOSTIC_FAILURE		0x40
781da177e4SLinus Torvalds #define SENCODE_INTERNAL_TARGET_FAILURE		0x44
791da177e4SLinus Torvalds #define SENCODE_INVALID_MESSAGE_ERROR		0x49
801da177e4SLinus Torvalds #define SENCODE_LUN_FAILED_SELF_CONFIG		0x4c
811da177e4SLinus Torvalds #define SENCODE_OVERLAPPED_COMMAND		0x4E
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds /*
841da177e4SLinus Torvalds  *	Additional sense codes
851da177e4SLinus Torvalds  */
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds #define ASENCODE_NO_SENSE			0x00
881da177e4SLinus Torvalds #define ASENCODE_END_OF_DATA			0x05
891da177e4SLinus Torvalds #define ASENCODE_BECOMING_READY			0x01
901da177e4SLinus Torvalds #define ASENCODE_INIT_CMD_REQUIRED		0x02
911da177e4SLinus Torvalds #define ASENCODE_PARAM_LIST_LENGTH_ERROR	0x00
921da177e4SLinus Torvalds #define ASENCODE_INVALID_COMMAND		0x00
931da177e4SLinus Torvalds #define ASENCODE_LBA_OUT_OF_RANGE		0x00
941da177e4SLinus Torvalds #define ASENCODE_INVALID_CDB_FIELD		0x00
951da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SUPPORTED		0x00
961da177e4SLinus Torvalds #define ASENCODE_INVALID_PARAM_FIELD		0x00
971da177e4SLinus Torvalds #define ASENCODE_PARAM_NOT_SUPPORTED		0x01
981da177e4SLinus Torvalds #define ASENCODE_PARAM_VALUE_INVALID		0x02
991da177e4SLinus Torvalds #define ASENCODE_RESET_OCCURRED			0x00
1001da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x00
1011da177e4SLinus Torvalds #define ASENCODE_INQUIRY_DATA_CHANGED		0x03
1021da177e4SLinus Torvalds #define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x00
1031da177e4SLinus Torvalds #define ASENCODE_DIAGNOSTIC_FAILURE		0x80
1041da177e4SLinus Torvalds #define ASENCODE_INTERNAL_TARGET_FAILURE	0x00
1051da177e4SLinus Torvalds #define ASENCODE_INVALID_MESSAGE_ERROR		0x00
1061da177e4SLinus Torvalds #define ASENCODE_LUN_FAILED_SELF_CONFIG		0x00
1071da177e4SLinus Torvalds #define ASENCODE_OVERLAPPED_COMMAND		0x00
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds #define BYTE0(x) (unsigned char)(x)
1101da177e4SLinus Torvalds #define BYTE1(x) (unsigned char)((x) >> 8)
1111da177e4SLinus Torvalds #define BYTE2(x) (unsigned char)((x) >> 16)
1121da177e4SLinus Torvalds #define BYTE3(x) (unsigned char)((x) >> 24)
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds /*------------------------------------------------------------------------------
1151da177e4SLinus Torvalds  *              S T R U C T S / T Y P E D E F S
1161da177e4SLinus Torvalds  *----------------------------------------------------------------------------*/
1171da177e4SLinus Torvalds /* SCSI inquiry data */
1181da177e4SLinus Torvalds struct inquiry_data {
1191da177e4SLinus Torvalds 	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type */
1201da177e4SLinus Torvalds 	u8 inqd_dtq;	/* RMB | Device Type Qualifier */
1211da177e4SLinus Torvalds 	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
1221da177e4SLinus Torvalds 	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
1231da177e4SLinus Torvalds 	u8 inqd_len;	/* Additional length (n-4) */
1241da177e4SLinus Torvalds 	u8 inqd_pad1[2];/* Reserved - must be zero */
1251da177e4SLinus Torvalds 	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
1261da177e4SLinus Torvalds 	u8 inqd_vid[8];	/* Vendor ID */
1271da177e4SLinus Torvalds 	u8 inqd_pid[16];/* Product ID */
1281da177e4SLinus Torvalds 	u8 inqd_prl[4];	/* Product Revision Level */
1291da177e4SLinus Torvalds };
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds /*
1321da177e4SLinus Torvalds  *              M O D U L E   G L O B A L S
1331da177e4SLinus Torvalds  */
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
1361da177e4SLinus Torvalds static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
1370e68c003SMark Haverkamp static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
1381da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
1391da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
1401da177e4SLinus Torvalds static char *aac_get_status_string(u32 status);
1411da177e4SLinus Torvalds #endif
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds /*
1441da177e4SLinus Torvalds  *	Non dasd selection is handled entirely in aachba now
1451da177e4SLinus Torvalds  */
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds static int nondasd = -1;
148d8e96507SLeubner, Achim static int aac_cache = 2;	/* WCE=0 to avoid performance problems */
1491da177e4SLinus Torvalds static int dacmode = -1;
1508ef22247SSalyzyn, Mark int aac_msi;
1511208bab5SSalyzyn, Mark int aac_commit = -1;
152404d9a90SMark Haverkamp int startup_timeout = 180;
153404d9a90SMark Haverkamp int aif_timeout = 120;
1541da177e4SLinus Torvalds 
1559a72f976SMark Haverkamp module_param(nondasd, int, S_IRUGO|S_IWUSR);
1568ef22247SSalyzyn, Mark MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
1578ef22247SSalyzyn, Mark 	" 0=off, 1=on");
15895e852e1SSalyzyn, Mark module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
1598ef22247SSalyzyn, Mark MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n"
1608ef22247SSalyzyn, Mark 	"\tbit 0 - Disable FUA in WRITE SCSI commands\n"
1618ef22247SSalyzyn, Mark 	"\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n"
162d8e96507SLeubner, Achim 	"\tbit 2 - Disable only if Battery is protecting Cache");
1639a72f976SMark Haverkamp module_param(dacmode, int, S_IRUGO|S_IWUSR);
1648ef22247SSalyzyn, Mark MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC."
1658ef22247SSalyzyn, Mark 	" 0=off, 1=on");
1661208bab5SSalyzyn, Mark module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
1678ef22247SSalyzyn, Mark MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
1688ef22247SSalyzyn, Mark 	" adapter for foreign arrays.\n"
1698ef22247SSalyzyn, Mark 	"This is typically needed in systems that do not have a BIOS."
1708ef22247SSalyzyn, Mark 	" 0=off, 1=on");
1718ef22247SSalyzyn, Mark module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
1728ef22247SSalyzyn, Mark MODULE_PARM_DESC(msi, "IRQ handling."
1738ef22247SSalyzyn, Mark 	" 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)");
174404d9a90SMark Haverkamp module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
1758ef22247SSalyzyn, Mark MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
1768ef22247SSalyzyn, Mark 	" adapter to have it's kernel up and\n"
1778ef22247SSalyzyn, Mark 	"running. This is typically adjusted for large systems that do not"
1788ef22247SSalyzyn, Mark 	" have a BIOS.");
179404d9a90SMark Haverkamp module_param(aif_timeout, int, S_IRUGO|S_IWUSR);
1808ef22247SSalyzyn, Mark MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for"
1818ef22247SSalyzyn, Mark 	" applications to pick up AIFs before\n"
1828ef22247SSalyzyn, Mark 	"deregistering them. This is typically adjusted for heavily burdened"
1838ef22247SSalyzyn, Mark 	" systems.");
1841da177e4SLinus Torvalds 
1857c00ffa3SMark Haverkamp  int numacb = -1;
1867c00ffa3SMark Haverkamp  module_param(numacb, int, S_IRUGO|S_IWUSR);
1878ef22247SSalyzyn, Mark MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control"
1888ef22247SSalyzyn, Mark 	" blocks (FIB) allocated. Valid values are 512 and down. Default is"
1898ef22247SSalyzyn, Mark 	" to use suggestion from Firmware.");
1907c00ffa3SMark Haverkamp  
1917c00ffa3SMark Haverkamp  int acbsize = -1;
1927c00ffa3SMark Haverkamp  module_param(acbsize, int, S_IRUGO|S_IWUSR);
1938ef22247SSalyzyn, Mark MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)"
1948ef22247SSalyzyn, Mark 	" size. Valid values are 512, 2048, 4096 and 8192. Default is to use"
1958ef22247SSalyzyn, Mark 	" suggestion from Firmware.");
196653ba58dSMark Haverkamp 
19729c97684SSalyzyn, Mark int update_interval = 30 * 60;
19829c97684SSalyzyn, Mark module_param(update_interval, int, S_IRUGO|S_IWUSR);
1998ef22247SSalyzyn, Mark MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync"
2008ef22247SSalyzyn, Mark 	" updates issued to adapter.");
20129c97684SSalyzyn, Mark 
20229c97684SSalyzyn, Mark int check_interval = 24 * 60 * 60;
20329c97684SSalyzyn, Mark module_param(check_interval, int, S_IRUGO|S_IWUSR);
2048ef22247SSalyzyn, Mark MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health"
2058ef22247SSalyzyn, Mark 	" checks.");
20629c97684SSalyzyn, Mark 
20787f3bda3SAndrew Morton int aac_check_reset = 1;
20887f3bda3SAndrew Morton module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
20995e7a8efSPaul Bolle MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the"
2108ef22247SSalyzyn, Mark 	" adapter. a value of -1 forces the reset to adapters programmed to"
2118ef22247SSalyzyn, Mark 	" ignore it.");
21229c97684SSalyzyn, Mark 
213e37ee4beSMark Haverkamp int expose_physicals = -1;
214653ba58dSMark Haverkamp module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
2158ef22247SSalyzyn, Mark MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays."
2168ef22247SSalyzyn, Mark 	" -1=protect 0=off, 1=on");
21703d44337SMark Haverkamp 
2188ef22247SSalyzyn, Mark int aac_reset_devices;
2191208bab5SSalyzyn, Mark module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR);
2201208bab5SSalyzyn, Mark MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization.");
22103d44337SMark Haverkamp 
222d8e96507SLeubner, Achim int aac_wwn = 1;
223d8e96507SLeubner, Achim module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR);
224d8e96507SLeubner, Achim MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n"
225d8e96507SLeubner, Achim 	"\t0 - Disable\n"
226d8e96507SLeubner, Achim 	"\t1 - Array Meta Data Signature (default)\n"
227d8e96507SLeubner, Achim 	"\t2 - Adapter Serial Number");
228d8e96507SLeubner, Achim 
229d8e96507SLeubner, Achim 
23003d44337SMark Haverkamp static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
23103d44337SMark Haverkamp 		struct fib *fibptr) {
23203d44337SMark Haverkamp 	struct scsi_device *device;
23303d44337SMark Haverkamp 
23403d44337SMark Haverkamp 	if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
235c835e372SSalyzyn, Mark 		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
23603d44337SMark Haverkamp 		aac_fib_complete(fibptr);
23703d44337SMark Haverkamp 		aac_fib_free(fibptr);
23803d44337SMark Haverkamp 		return 0;
23903d44337SMark Haverkamp 	}
24003d44337SMark Haverkamp 	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
24103d44337SMark Haverkamp 	device = scsicmd->device;
24203d44337SMark Haverkamp 	if (unlikely(!device || !scsi_device_online(device))) {
24303d44337SMark Haverkamp 		dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
24403d44337SMark Haverkamp 		aac_fib_complete(fibptr);
24503d44337SMark Haverkamp 		aac_fib_free(fibptr);
24603d44337SMark Haverkamp 		return 0;
24703d44337SMark Haverkamp 	}
24803d44337SMark Haverkamp 	return 1;
24903d44337SMark Haverkamp }
25003d44337SMark Haverkamp 
2511da177e4SLinus Torvalds /**
2521da177e4SLinus Torvalds  *	aac_get_config_status	-	check the adapter configuration
2531da177e4SLinus Torvalds  *	@common: adapter to query
2541da177e4SLinus Torvalds  *
2551da177e4SLinus Torvalds  *	Query config status, and commit the configuration if needed.
2561da177e4SLinus Torvalds  */
2578c867b25SMark Haverkamp int aac_get_config_status(struct aac_dev *dev, int commit_flag)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds 	int status = 0;
2601da177e4SLinus Torvalds 	struct fib * fibptr;
2611da177e4SLinus Torvalds 
262bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
2631da177e4SLinus Torvalds 		return -ENOMEM;
2641da177e4SLinus Torvalds 
265bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
2661da177e4SLinus Torvalds 	{
2671da177e4SLinus Torvalds 		struct aac_get_config_status *dinfo;
2681da177e4SLinus Torvalds 		dinfo = (struct aac_get_config_status *) fib_data(fibptr);
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 		dinfo->command = cpu_to_le32(VM_ContainerConfig);
2711da177e4SLinus Torvalds 		dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
2721da177e4SLinus Torvalds 		dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
2731da177e4SLinus Torvalds 	}
2741da177e4SLinus Torvalds 
275bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
2761da177e4SLinus Torvalds 			    fibptr,
2771da177e4SLinus Torvalds 			    sizeof (struct aac_get_config_status),
2781da177e4SLinus Torvalds 			    FsaNormal,
2791da177e4SLinus Torvalds 			    1, 1,
2801da177e4SLinus Torvalds 			    NULL, NULL);
2811da177e4SLinus Torvalds 	if (status < 0) {
2821da177e4SLinus Torvalds 		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
2831da177e4SLinus Torvalds 	} else {
2841da177e4SLinus Torvalds 		struct aac_get_config_status_resp *reply
2851da177e4SLinus Torvalds 		  = (struct aac_get_config_status_resp *) fib_data(fibptr);
2861da177e4SLinus Torvalds 		dprintk((KERN_WARNING
2871da177e4SLinus Torvalds 		  "aac_get_config_status: response=%d status=%d action=%d\n",
2881da177e4SLinus Torvalds 		  le32_to_cpu(reply->response),
2891da177e4SLinus Torvalds 		  le32_to_cpu(reply->status),
2901da177e4SLinus Torvalds 		  le32_to_cpu(reply->data.action)));
2911da177e4SLinus Torvalds 		if ((le32_to_cpu(reply->response) != ST_OK) ||
2921da177e4SLinus Torvalds 		     (le32_to_cpu(reply->status) != CT_OK) ||
2931da177e4SLinus Torvalds 		     (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
2941da177e4SLinus Torvalds 			printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
2951da177e4SLinus Torvalds 			status = -EINVAL;
2961da177e4SLinus Torvalds 		}
2971da177e4SLinus Torvalds 	}
298cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* Do not set XferState to zero unless receives a response from F/W */
299cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status >= 0)
300bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
301cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
3021da177e4SLinus Torvalds 	/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
3031da177e4SLinus Torvalds 	if (status >= 0) {
3041208bab5SSalyzyn, Mark 		if ((aac_commit == 1) || commit_flag) {
3051da177e4SLinus Torvalds 			struct aac_commit_config * dinfo;
306bfb35aa8SMark Haverkamp 			aac_fib_init(fibptr);
3071da177e4SLinus Torvalds 			dinfo = (struct aac_commit_config *) fib_data(fibptr);
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 			dinfo->command = cpu_to_le32(VM_ContainerConfig);
3101da177e4SLinus Torvalds 			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
3111da177e4SLinus Torvalds 
312bfb35aa8SMark Haverkamp 			status = aac_fib_send(ContainerCommand,
3131da177e4SLinus Torvalds 				    fibptr,
3141da177e4SLinus Torvalds 				    sizeof (struct aac_commit_config),
3151da177e4SLinus Torvalds 				    FsaNormal,
3161da177e4SLinus Torvalds 				    1, 1,
3171da177e4SLinus Torvalds 				    NULL, NULL);
318cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			/* Do not set XferState to zero unless
319cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			 * receives a response from F/W */
320cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			if (status >= 0)
321bfb35aa8SMark Haverkamp 				aac_fib_complete(fibptr);
3221208bab5SSalyzyn, Mark 		} else if (aac_commit == 0) {
3231da177e4SLinus Torvalds 			printk(KERN_WARNING
3241da177e4SLinus Torvalds 			  "aac_get_config_status: Foreign device configurations are being ignored\n");
3251da177e4SLinus Torvalds 		}
3261da177e4SLinus Torvalds 	}
327cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
328cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status != -ERESTARTSYS)
329bfb35aa8SMark Haverkamp 		aac_fib_free(fibptr);
3301da177e4SLinus Torvalds 	return status;
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds 
333e3cc268fSRajashekhara, Mahesh static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
334e3cc268fSRajashekhara, Mahesh {
335e3cc268fSRajashekhara, Mahesh 	char inq_data;
336e3cc268fSRajashekhara, Mahesh 	scsi_sg_copy_to_buffer(scsicmd,  &inq_data, sizeof(inq_data));
337e3cc268fSRajashekhara, Mahesh 	if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
338e3cc268fSRajashekhara, Mahesh 		inq_data &= 0xdf;
339e3cc268fSRajashekhara, Mahesh 		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
340e3cc268fSRajashekhara, Mahesh 	}
341e3cc268fSRajashekhara, Mahesh }
342e3cc268fSRajashekhara, Mahesh 
3431da177e4SLinus Torvalds /**
3441da177e4SLinus Torvalds  *	aac_get_containers	-	list containers
3451da177e4SLinus Torvalds  *	@common: adapter to probe
3461da177e4SLinus Torvalds  *
3471da177e4SLinus Torvalds  *	Make a list of all containers on this controller
3481da177e4SLinus Torvalds  */
3491da177e4SLinus Torvalds int aac_get_containers(struct aac_dev *dev)
3501da177e4SLinus Torvalds {
3511da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
3521da177e4SLinus Torvalds 	u32 index;
3531da177e4SLinus Torvalds 	int status = 0;
3541da177e4SLinus Torvalds 	struct fib * fibptr;
3551da177e4SLinus Torvalds 	struct aac_get_container_count *dinfo;
3561da177e4SLinus Torvalds 	struct aac_get_container_count_resp *dresp;
3571da177e4SLinus Torvalds 	int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
3581da177e4SLinus Torvalds 
359bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
3601da177e4SLinus Torvalds 		return -ENOMEM;
3611da177e4SLinus Torvalds 
362bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
3631da177e4SLinus Torvalds 	dinfo = (struct aac_get_container_count *) fib_data(fibptr);
3641da177e4SLinus Torvalds 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
3651da177e4SLinus Torvalds 	dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
3661da177e4SLinus Torvalds 
367bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
3681da177e4SLinus Torvalds 		    fibptr,
3691da177e4SLinus Torvalds 		    sizeof (struct aac_get_container_count),
3701da177e4SLinus Torvalds 		    FsaNormal,
3711da177e4SLinus Torvalds 		    1, 1,
3721da177e4SLinus Torvalds 		    NULL, NULL);
3731da177e4SLinus Torvalds 	if (status >= 0) {
3741da177e4SLinus Torvalds 		dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
3751da177e4SLinus Torvalds 		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
376bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
3771da177e4SLinus Torvalds 	}
378cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
379cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (status != -ERESTARTSYS)
380fe76df42SMark Haverkamp 		aac_fib_free(fibptr);
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
3831da177e4SLinus Torvalds 		maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
3841a655040SSalyzyn, Mark 	fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
385fe76df42SMark Haverkamp 			GFP_KERNEL);
386fe76df42SMark Haverkamp 	if (!fsa_dev_ptr)
3871da177e4SLinus Torvalds 		return -ENOMEM;
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	dev->fsa_dev = fsa_dev_ptr;
3901da177e4SLinus Torvalds 	dev->maximum_num_containers = maximum_num_containers;
3911da177e4SLinus Torvalds 
392fe76df42SMark Haverkamp 	for (index = 0; index < dev->maximum_num_containers; ) {
3931da177e4SLinus Torvalds 		fsa_dev_ptr[index].devname[0] = '\0';
3941da177e4SLinus Torvalds 
395fe76df42SMark Haverkamp 		status = aac_probe_container(dev, index);
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 		if (status < 0) {
3981da177e4SLinus Torvalds 			printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
3991da177e4SLinus Torvalds 			break;
4001da177e4SLinus Torvalds 		}
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 		/*
4031da177e4SLinus Torvalds 		 *	If there are no more containers, then stop asking.
4041da177e4SLinus Torvalds 		 */
405fe76df42SMark Haverkamp 		if (++index >= status)
4061da177e4SLinus Torvalds 			break;
4071da177e4SLinus Torvalds 	}
4081da177e4SLinus Torvalds 	return status;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds static void get_container_name_callback(void *context, struct fib * fibptr)
4121da177e4SLinus Torvalds {
4131da177e4SLinus Torvalds 	struct aac_get_name_resp * get_name_reply;
4141da177e4SLinus Torvalds 	struct scsi_cmnd * scsicmd;
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
4171da177e4SLinus Torvalds 
41803d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
41903d44337SMark Haverkamp 		return;
42003d44337SMark Haverkamp 
4211da177e4SLinus Torvalds 	dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
422125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
4251da177e4SLinus Torvalds 	/* Failure is irrelevant, using default value instead */
4261da177e4SLinus Torvalds 	if ((le32_to_cpu(get_name_reply->status) == CT_OK)
4271da177e4SLinus Torvalds 	 && (get_name_reply->data[0] != '\0')) {
4281da177e4SLinus Torvalds 		char *sp = get_name_reply->data;
4291da177e4SLinus Torvalds 		sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0';
4301da177e4SLinus Torvalds 		while (*sp == ' ')
4311da177e4SLinus Torvalds 			++sp;
4323b2946ccSMark Haverkamp 		if (*sp) {
433d4345028SFUJITA Tomonori 			struct inquiry_data inq;
4343b2946ccSMark Haverkamp 			char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
4353b2946ccSMark Haverkamp 			int count = sizeof(d);
4363b2946ccSMark Haverkamp 			char *dp = d;
4373b2946ccSMark Haverkamp 			do {
4381da177e4SLinus Torvalds 				*dp++ = (*sp) ? *sp++ : ' ';
4391da177e4SLinus Torvalds 			} while (--count > 0);
440d4345028SFUJITA Tomonori 
441d4345028SFUJITA Tomonori 			scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq));
442d4345028SFUJITA Tomonori 			memcpy(inq.inqd_pid, d, sizeof(d));
443d4345028SFUJITA Tomonori 			scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq));
4441da177e4SLinus Torvalds 		}
4453b2946ccSMark Haverkamp 	}
4463b2946ccSMark Haverkamp 
4471da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
4481da177e4SLinus Torvalds 
449bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
450bfb35aa8SMark Haverkamp 	aac_fib_free(fibptr);
4518e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
4521da177e4SLinus Torvalds }
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds /**
4551da177e4SLinus Torvalds  *	aac_get_container_name	-	get container name, none blocking.
4561da177e4SLinus Torvalds  */
4579e7c349cSMark Haverkamp static int aac_get_container_name(struct scsi_cmnd * scsicmd)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	int status;
4601da177e4SLinus Torvalds 	struct aac_get_name *dinfo;
4611da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
4621da177e4SLinus Torvalds 	struct aac_dev * dev;
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
4651da177e4SLinus Torvalds 
466bfb35aa8SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(dev)))
4671da177e4SLinus Torvalds 		return -ENOMEM;
4681da177e4SLinus Torvalds 
469bfb35aa8SMark Haverkamp 	aac_fib_init(cmd_fibcontext);
4701da177e4SLinus Torvalds 	dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
4731da177e4SLinus Torvalds 	dinfo->type = cpu_to_le32(CT_READ_NAME);
4749e7c349cSMark Haverkamp 	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
4751da177e4SLinus Torvalds 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
4761da177e4SLinus Torvalds 
477bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
4781da177e4SLinus Torvalds 		  cmd_fibcontext,
4791da177e4SLinus Torvalds 		  sizeof (struct aac_get_name),
4801da177e4SLinus Torvalds 		  FsaNormal,
4811da177e4SLinus Torvalds 		  0, 1,
4821da177e4SLinus Torvalds 		  (fib_callback)get_container_name_callback,
4831da177e4SLinus Torvalds 		  (void *) scsicmd);
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 	/*
4861da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
4871da177e4SLinus Torvalds 	 */
48877d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
48977d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
4901da177e4SLinus Torvalds 		return 0;
49177d644d4SMark Haverkamp 	}
4921da177e4SLinus Torvalds 
493bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
494bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
495bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
4961da177e4SLinus Torvalds 	return -1;
4971da177e4SLinus Torvalds }
4981da177e4SLinus Torvalds 
499fe76df42SMark Haverkamp static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
500fe76df42SMark Haverkamp {
501fe76df42SMark Haverkamp 	struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
502fe76df42SMark Haverkamp 
5031a655040SSalyzyn, Mark 	if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))
504fe76df42SMark Haverkamp 		return aac_scsi_cmd(scsicmd);
505fe76df42SMark Haverkamp 
506fe76df42SMark Haverkamp 	scsicmd->result = DID_NO_CONNECT << 16;
507fe76df42SMark Haverkamp 	scsicmd->scsi_done(scsicmd);
508fe76df42SMark Haverkamp 	return 0;
509fe76df42SMark Haverkamp }
510fe76df42SMark Haverkamp 
5111a655040SSalyzyn, Mark static void _aac_probe_container2(void * context, struct fib * fibptr)
512fe76df42SMark Haverkamp {
51303d44337SMark Haverkamp 	struct fsa_dev_info *fsa_dev_ptr;
514fe76df42SMark Haverkamp 	int (*callback)(struct scsi_cmnd *);
51503d44337SMark Haverkamp 	struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
51603d44337SMark Haverkamp 
51703d44337SMark Haverkamp 
5181a655040SSalyzyn, Mark 	if (!aac_valid_context(scsicmd, fibptr))
5191a655040SSalyzyn, Mark 		return;
520fe76df42SMark Haverkamp 
521fe76df42SMark Haverkamp 	scsicmd->SCp.Status = 0;
5221a655040SSalyzyn, Mark 	fsa_dev_ptr = fibptr->dev->fsa_dev;
523fe76df42SMark Haverkamp 	if (fsa_dev_ptr) {
524fe76df42SMark Haverkamp 		struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
525fe76df42SMark Haverkamp 		fsa_dev_ptr += scmd_id(scsicmd);
526fe76df42SMark Haverkamp 
527fe76df42SMark Haverkamp 		if ((le32_to_cpu(dresp->status) == ST_OK) &&
528fe76df42SMark Haverkamp 		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
529fe76df42SMark Haverkamp 		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
530fe76df42SMark Haverkamp 			fsa_dev_ptr->valid = 1;
531655d722cSMark Salyzyn 			/* sense_key holds the current state of the spin-up */
532655d722cSMark Salyzyn 			if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
533655d722cSMark Salyzyn 				fsa_dev_ptr->sense_data.sense_key = NOT_READY;
534655d722cSMark Salyzyn 			else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
535655d722cSMark Salyzyn 				fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
536fe76df42SMark Haverkamp 			fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
537fe76df42SMark Haverkamp 			fsa_dev_ptr->size
538fe76df42SMark Haverkamp 			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
539fe76df42SMark Haverkamp 			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
540fe76df42SMark Haverkamp 			fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
541fe76df42SMark Haverkamp 		}
542fe76df42SMark Haverkamp 		if ((fsa_dev_ptr->valid & 1) == 0)
543fe76df42SMark Haverkamp 			fsa_dev_ptr->valid = 0;
544fe76df42SMark Haverkamp 		scsicmd->SCp.Status = le32_to_cpu(dresp->count);
545fe76df42SMark Haverkamp 	}
546fe76df42SMark Haverkamp 	aac_fib_complete(fibptr);
547fe76df42SMark Haverkamp 	aac_fib_free(fibptr);
548fe76df42SMark Haverkamp 	callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
549fe76df42SMark Haverkamp 	scsicmd->SCp.ptr = NULL;
5501a655040SSalyzyn, Mark 	(*callback)(scsicmd);
5511a655040SSalyzyn, Mark 	return;
552fe76df42SMark Haverkamp }
553fe76df42SMark Haverkamp 
5541a655040SSalyzyn, Mark static void _aac_probe_container1(void * context, struct fib * fibptr)
555fe76df42SMark Haverkamp {
556fe76df42SMark Haverkamp 	struct scsi_cmnd * scsicmd;
557fe76df42SMark Haverkamp 	struct aac_mount * dresp;
558fe76df42SMark Haverkamp 	struct aac_query_mount *dinfo;
559fe76df42SMark Haverkamp 	int status;
560fe76df42SMark Haverkamp 
561fe76df42SMark Haverkamp 	dresp = (struct aac_mount *) fib_data(fibptr);
562fe76df42SMark Haverkamp 	dresp->mnt[0].capacityhigh = 0;
563fe76df42SMark Haverkamp 	if ((le32_to_cpu(dresp->status) != ST_OK) ||
5641a655040SSalyzyn, Mark 	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
5651a655040SSalyzyn, Mark 		_aac_probe_container2(context, fibptr);
5661a655040SSalyzyn, Mark 		return;
5671a655040SSalyzyn, Mark 	}
568fe76df42SMark Haverkamp 	scsicmd = (struct scsi_cmnd *) context;
569fe76df42SMark Haverkamp 
57003d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
5711a655040SSalyzyn, Mark 		return;
57203d44337SMark Haverkamp 
573fe76df42SMark Haverkamp 	aac_fib_init(fibptr);
574fe76df42SMark Haverkamp 
575fe76df42SMark Haverkamp 	dinfo = (struct aac_query_mount *)fib_data(fibptr);
576fe76df42SMark Haverkamp 
577fe76df42SMark Haverkamp 	dinfo->command = cpu_to_le32(VM_NameServe64);
578fe76df42SMark Haverkamp 	dinfo->count = cpu_to_le32(scmd_id(scsicmd));
579fe76df42SMark Haverkamp 	dinfo->type = cpu_to_le32(FT_FILESYS);
580fe76df42SMark Haverkamp 
581fe76df42SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
582fe76df42SMark Haverkamp 			  fibptr,
583fe76df42SMark Haverkamp 			  sizeof(struct aac_query_mount),
584fe76df42SMark Haverkamp 			  FsaNormal,
585fe76df42SMark Haverkamp 			  0, 1,
5861a655040SSalyzyn, Mark 			  _aac_probe_container2,
587fe76df42SMark Haverkamp 			  (void *) scsicmd);
588fe76df42SMark Haverkamp 	/*
589fe76df42SMark Haverkamp 	 *	Check that the command queued to the controller
590fe76df42SMark Haverkamp 	 */
5911a655040SSalyzyn, Mark 	if (status == -EINPROGRESS)
592fe76df42SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
5931a655040SSalyzyn, Mark 	else if (status < 0) {
594fe76df42SMark Haverkamp 		/* Inherit results from VM_NameServe, if any */
595fe76df42SMark Haverkamp 		dresp->status = cpu_to_le32(ST_OK);
5961a655040SSalyzyn, Mark 		_aac_probe_container2(context, fibptr);
597fe76df42SMark Haverkamp 	}
598fe76df42SMark Haverkamp }
599fe76df42SMark Haverkamp 
600fe76df42SMark Haverkamp static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
601fe76df42SMark Haverkamp {
602fe76df42SMark Haverkamp 	struct fib * fibptr;
603fe76df42SMark Haverkamp 	int status = -ENOMEM;
604fe76df42SMark Haverkamp 
605fe76df42SMark Haverkamp 	if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
606fe76df42SMark Haverkamp 		struct aac_query_mount *dinfo;
607fe76df42SMark Haverkamp 
608fe76df42SMark Haverkamp 		aac_fib_init(fibptr);
609fe76df42SMark Haverkamp 
610fe76df42SMark Haverkamp 		dinfo = (struct aac_query_mount *)fib_data(fibptr);
611fe76df42SMark Haverkamp 
612fe76df42SMark Haverkamp 		dinfo->command = cpu_to_le32(VM_NameServe);
613fe76df42SMark Haverkamp 		dinfo->count = cpu_to_le32(scmd_id(scsicmd));
614fe76df42SMark Haverkamp 		dinfo->type = cpu_to_le32(FT_FILESYS);
615fe76df42SMark Haverkamp 		scsicmd->SCp.ptr = (char *)callback;
616fe76df42SMark Haverkamp 
617fe76df42SMark Haverkamp 		status = aac_fib_send(ContainerCommand,
618fe76df42SMark Haverkamp 			  fibptr,
619fe76df42SMark Haverkamp 			  sizeof(struct aac_query_mount),
620fe76df42SMark Haverkamp 			  FsaNormal,
621fe76df42SMark Haverkamp 			  0, 1,
6221a655040SSalyzyn, Mark 			  _aac_probe_container1,
623fe76df42SMark Haverkamp 			  (void *) scsicmd);
624fe76df42SMark Haverkamp 		/*
625fe76df42SMark Haverkamp 		 *	Check that the command queued to the controller
626fe76df42SMark Haverkamp 		 */
627fe76df42SMark Haverkamp 		if (status == -EINPROGRESS) {
628fe76df42SMark Haverkamp 			scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
629fe76df42SMark Haverkamp 			return 0;
630fe76df42SMark Haverkamp 		}
631fe76df42SMark Haverkamp 		if (status < 0) {
632fe76df42SMark Haverkamp 			scsicmd->SCp.ptr = NULL;
633fe76df42SMark Haverkamp 			aac_fib_complete(fibptr);
634fe76df42SMark Haverkamp 			aac_fib_free(fibptr);
635fe76df42SMark Haverkamp 		}
636fe76df42SMark Haverkamp 	}
637fe76df42SMark Haverkamp 	if (status < 0) {
638fe76df42SMark Haverkamp 		struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
639fe76df42SMark Haverkamp 		if (fsa_dev_ptr) {
640fe76df42SMark Haverkamp 			fsa_dev_ptr += scmd_id(scsicmd);
641fe76df42SMark Haverkamp 			if ((fsa_dev_ptr->valid & 1) == 0) {
642fe76df42SMark Haverkamp 				fsa_dev_ptr->valid = 0;
643fe76df42SMark Haverkamp 				return (*callback)(scsicmd);
644fe76df42SMark Haverkamp 			}
645fe76df42SMark Haverkamp 		}
646fe76df42SMark Haverkamp 	}
647fe76df42SMark Haverkamp 	return status;
648fe76df42SMark Haverkamp }
649fe76df42SMark Haverkamp 
6501da177e4SLinus Torvalds /**
651bfb35aa8SMark Haverkamp  *	aac_probe_container		-	query a logical volume
6521da177e4SLinus Torvalds  *	@dev: device to query
6531da177e4SLinus Torvalds  *	@cid: container identifier
6541da177e4SLinus Torvalds  *
6551da177e4SLinus Torvalds  *	Queries the controller about the given volume. The volume information
6561da177e4SLinus Torvalds  *	is updated in the struct fsa_dev_info structure rather than returned.
6571da177e4SLinus Torvalds  */
658fe76df42SMark Haverkamp static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
659fe76df42SMark Haverkamp {
660fe76df42SMark Haverkamp 	scsicmd->device = NULL;
661fe76df42SMark Haverkamp 	return 0;
662fe76df42SMark Haverkamp }
6631da177e4SLinus Torvalds 
664bfb35aa8SMark Haverkamp int aac_probe_container(struct aac_dev *dev, int cid)
6651da177e4SLinus Torvalds {
666fe76df42SMark Haverkamp 	struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
667fe76df42SMark Haverkamp 	struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
6681da177e4SLinus Torvalds 	int status;
6691da177e4SLinus Torvalds 
670fe76df42SMark Haverkamp 	if (!scsicmd || !scsidev) {
671fe76df42SMark Haverkamp 		kfree(scsicmd);
672fe76df42SMark Haverkamp 		kfree(scsidev);
67390ee3466SMark Haverkamp 		return -ENOMEM;
6741da177e4SLinus Torvalds 	}
675fe76df42SMark Haverkamp 	scsicmd->list.next = NULL;
6761a655040SSalyzyn, Mark 	scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;
6771da177e4SLinus Torvalds 
678fe76df42SMark Haverkamp 	scsicmd->device = scsidev;
679fe76df42SMark Haverkamp 	scsidev->sdev_state = 0;
680fe76df42SMark Haverkamp 	scsidev->id = cid;
681fe76df42SMark Haverkamp 	scsidev->host = dev->scsi_host_ptr;
6821da177e4SLinus Torvalds 
683fe76df42SMark Haverkamp 	if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
684fe76df42SMark Haverkamp 		while (scsicmd->device == scsidev)
685fe76df42SMark Haverkamp 			schedule();
686802ae2f0SSalyzyn, Mark 	kfree(scsidev);
687fe76df42SMark Haverkamp 	status = scsicmd->SCp.Status;
688fe76df42SMark Haverkamp 	kfree(scsicmd);
6891da177e4SLinus Torvalds 	return status;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds /* Local Structure to set SCSI inquiry data strings */
6931da177e4SLinus Torvalds struct scsi_inq {
6941da177e4SLinus Torvalds 	char vid[8];         /* Vendor ID */
6951da177e4SLinus Torvalds 	char pid[16];        /* Product ID */
6961da177e4SLinus Torvalds 	char prl[4];         /* Product Revision Level */
6971da177e4SLinus Torvalds };
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds /**
7001da177e4SLinus Torvalds  *	InqStrCopy	-	string merge
7011da177e4SLinus Torvalds  *	@a:	string to copy from
7021da177e4SLinus Torvalds  *	@b:	string to copy to
7031da177e4SLinus Torvalds  *
7041da177e4SLinus Torvalds  *	Copy a String from one location to another
7051da177e4SLinus Torvalds  *	without copying \0
7061da177e4SLinus Torvalds  */
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds static void inqstrcpy(char *a, char *b)
7091da177e4SLinus Torvalds {
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	while (*a != (char)0)
7121da177e4SLinus Torvalds 		*b++ = *a++;
7131da177e4SLinus Torvalds }
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds static char *container_types[] = {
7161da177e4SLinus Torvalds 	"None",
7171da177e4SLinus Torvalds 	"Volume",
7181da177e4SLinus Torvalds 	"Mirror",
7191da177e4SLinus Torvalds 	"Stripe",
7201da177e4SLinus Torvalds 	"RAID5",
7211da177e4SLinus Torvalds 	"SSRW",
7221da177e4SLinus Torvalds 	"SSRO",
7231da177e4SLinus Torvalds 	"Morph",
7241da177e4SLinus Torvalds 	"Legacy",
7251da177e4SLinus Torvalds 	"RAID4",
7261da177e4SLinus Torvalds 	"RAID10",
7271da177e4SLinus Torvalds 	"RAID00",
7281da177e4SLinus Torvalds 	"V-MIRRORS",
7291da177e4SLinus Torvalds 	"PSEUDO R4",
7301da177e4SLinus Torvalds 	"RAID50",
73184971738SMark Haverkamp 	"RAID5D",
73284971738SMark Haverkamp 	"RAID5D0",
73384971738SMark Haverkamp 	"RAID1E",
73484971738SMark Haverkamp 	"RAID6",
73584971738SMark Haverkamp 	"RAID60",
7361da177e4SLinus Torvalds 	"Unknown"
7371da177e4SLinus Torvalds };
7381da177e4SLinus Torvalds 
73917eaaceeSSalyzyn, Mark char * get_container_type(unsigned tindex)
74017eaaceeSSalyzyn, Mark {
74117eaaceeSSalyzyn, Mark 	if (tindex >= ARRAY_SIZE(container_types))
74217eaaceeSSalyzyn, Mark 		tindex = ARRAY_SIZE(container_types) - 1;
74317eaaceeSSalyzyn, Mark 	return container_types[tindex];
74417eaaceeSSalyzyn, Mark }
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds /* Function: setinqstr
7471da177e4SLinus Torvalds  *
7481da177e4SLinus Torvalds  * Arguments: [1] pointer to void [1] int
7491da177e4SLinus Torvalds  *
7501da177e4SLinus Torvalds  * Purpose: Sets SCSI inquiry data strings for vendor, product
75125985edcSLucas De Marchi  * and revision level. Allows strings to be set in platform dependent
75225985edcSLucas De Marchi  * files instead of in OS dependent driver source.
7531da177e4SLinus Torvalds  */
7541da177e4SLinus Torvalds 
755794d0601SMark Haverkamp static void setinqstr(struct aac_dev *dev, void *data, int tindex)
7561da177e4SLinus Torvalds {
7571da177e4SLinus Torvalds 	struct scsi_inq *str;
7581da177e4SLinus Torvalds 
7591da177e4SLinus Torvalds 	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
760794d0601SMark Haverkamp 	memset(str, ' ', sizeof(*str));
761794d0601SMark Haverkamp 
762794d0601SMark Haverkamp 	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
763794d0601SMark Haverkamp 		char * cp = dev->supplement_adapter_info.AdapterTypeText;
7643bc8070fSSalyzyn, Mark 		int c;
7653bc8070fSSalyzyn, Mark 		if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
7663bc8070fSSalyzyn, Mark 			inqstrcpy("SMC", str->vid);
7673bc8070fSSalyzyn, Mark 		else {
7683bc8070fSSalyzyn, Mark 			c = sizeof(str->vid);
769794d0601SMark Haverkamp 			while (*cp && *cp != ' ' && --c)
770794d0601SMark Haverkamp 				++cp;
771794d0601SMark Haverkamp 			c = *cp;
772794d0601SMark Haverkamp 			*cp = '\0';
773794d0601SMark Haverkamp 			inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
774794d0601SMark Haverkamp 				   str->vid);
775794d0601SMark Haverkamp 			*cp = c;
776794d0601SMark Haverkamp 			while (*cp && *cp != ' ')
777794d0601SMark Haverkamp 				++cp;
7783bc8070fSSalyzyn, Mark 		}
779794d0601SMark Haverkamp 		while (*cp == ' ')
780794d0601SMark Haverkamp 			++cp;
781794d0601SMark Haverkamp 		/* last six chars reserved for vol type */
782794d0601SMark Haverkamp 		c = 0;
783794d0601SMark Haverkamp 		if (strlen(cp) > sizeof(str->pid)) {
784794d0601SMark Haverkamp 			c = cp[sizeof(str->pid)];
785794d0601SMark Haverkamp 			cp[sizeof(str->pid)] = '\0';
786794d0601SMark Haverkamp 		}
787794d0601SMark Haverkamp 		inqstrcpy (cp, str->pid);
788794d0601SMark Haverkamp 		if (c)
789794d0601SMark Haverkamp 			cp[sizeof(str->pid)] = c;
790794d0601SMark Haverkamp 	} else {
791794d0601SMark Haverkamp 		struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 		inqstrcpy (mp->vname, str->vid);
794794d0601SMark Haverkamp 		/* last six chars reserved for vol type */
795794d0601SMark Haverkamp 		inqstrcpy (mp->model, str->pid);
796794d0601SMark Haverkamp 	}
7971da177e4SLinus Torvalds 
7986391a113STobias Klauser 	if (tindex < ARRAY_SIZE(container_types)){
7991da177e4SLinus Torvalds 		char *findit = str->pid;
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 		for ( ; *findit != ' '; findit++); /* walk till we find a space */
8021da177e4SLinus Torvalds 		/* RAID is superfluous in the context of a RAID device */
8031da177e4SLinus Torvalds 		if (memcmp(findit-4, "RAID", 4) == 0)
8041da177e4SLinus Torvalds 			*(findit -= 4) = ' ';
805794d0601SMark Haverkamp 		if (((findit - str->pid) + strlen(container_types[tindex]))
806794d0601SMark Haverkamp 		 < (sizeof(str->pid) + sizeof(str->prl)))
8071da177e4SLinus Torvalds 			inqstrcpy (container_types[tindex], findit + 1);
8081da177e4SLinus Torvalds 	}
8091da177e4SLinus Torvalds 	inqstrcpy ("V1.0", str->prl);
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
81288e2f98eSSalyzyn, Mark static void get_container_serial_callback(void *context, struct fib * fibptr)
81388e2f98eSSalyzyn, Mark {
81488e2f98eSSalyzyn, Mark 	struct aac_get_serial_resp * get_serial_reply;
81588e2f98eSSalyzyn, Mark 	struct scsi_cmnd * scsicmd;
81688e2f98eSSalyzyn, Mark 
81788e2f98eSSalyzyn, Mark 	BUG_ON(fibptr == NULL);
81888e2f98eSSalyzyn, Mark 
81988e2f98eSSalyzyn, Mark 	scsicmd = (struct scsi_cmnd *) context;
82088e2f98eSSalyzyn, Mark 	if (!aac_valid_context(scsicmd, fibptr))
82188e2f98eSSalyzyn, Mark 		return;
82288e2f98eSSalyzyn, Mark 
82388e2f98eSSalyzyn, Mark 	get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
82488e2f98eSSalyzyn, Mark 	/* Failure is irrelevant, using default value instead */
82588e2f98eSSalyzyn, Mark 	if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
82688e2f98eSSalyzyn, Mark 		char sp[13];
82788e2f98eSSalyzyn, Mark 		/* EVPD bit set */
82888e2f98eSSalyzyn, Mark 		sp[0] = INQD_PDT_DA;
82988e2f98eSSalyzyn, Mark 		sp[1] = scsicmd->cmnd[2];
83088e2f98eSSalyzyn, Mark 		sp[2] = 0;
83188e2f98eSSalyzyn, Mark 		sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
83288e2f98eSSalyzyn, Mark 		  le32_to_cpu(get_serial_reply->uid));
833d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp));
83488e2f98eSSalyzyn, Mark 	}
83588e2f98eSSalyzyn, Mark 
83688e2f98eSSalyzyn, Mark 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
83788e2f98eSSalyzyn, Mark 
83888e2f98eSSalyzyn, Mark 	aac_fib_complete(fibptr);
83988e2f98eSSalyzyn, Mark 	aac_fib_free(fibptr);
84088e2f98eSSalyzyn, Mark 	scsicmd->scsi_done(scsicmd);
84188e2f98eSSalyzyn, Mark }
84288e2f98eSSalyzyn, Mark 
84388e2f98eSSalyzyn, Mark /**
84488e2f98eSSalyzyn, Mark  *	aac_get_container_serial - get container serial, none blocking.
84588e2f98eSSalyzyn, Mark  */
84688e2f98eSSalyzyn, Mark static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
84788e2f98eSSalyzyn, Mark {
84888e2f98eSSalyzyn, Mark 	int status;
84988e2f98eSSalyzyn, Mark 	struct aac_get_serial *dinfo;
85088e2f98eSSalyzyn, Mark 	struct fib * cmd_fibcontext;
85188e2f98eSSalyzyn, Mark 	struct aac_dev * dev;
85288e2f98eSSalyzyn, Mark 
85388e2f98eSSalyzyn, Mark 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
85488e2f98eSSalyzyn, Mark 
85588e2f98eSSalyzyn, Mark 	if (!(cmd_fibcontext = aac_fib_alloc(dev)))
85688e2f98eSSalyzyn, Mark 		return -ENOMEM;
85788e2f98eSSalyzyn, Mark 
85888e2f98eSSalyzyn, Mark 	aac_fib_init(cmd_fibcontext);
85988e2f98eSSalyzyn, Mark 	dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
86088e2f98eSSalyzyn, Mark 
86188e2f98eSSalyzyn, Mark 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
86288e2f98eSSalyzyn, Mark 	dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
86388e2f98eSSalyzyn, Mark 	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
86488e2f98eSSalyzyn, Mark 
86588e2f98eSSalyzyn, Mark 	status = aac_fib_send(ContainerCommand,
86688e2f98eSSalyzyn, Mark 		  cmd_fibcontext,
86788e2f98eSSalyzyn, Mark 		  sizeof (struct aac_get_serial),
86888e2f98eSSalyzyn, Mark 		  FsaNormal,
86988e2f98eSSalyzyn, Mark 		  0, 1,
87088e2f98eSSalyzyn, Mark 		  (fib_callback) get_container_serial_callback,
87188e2f98eSSalyzyn, Mark 		  (void *) scsicmd);
87288e2f98eSSalyzyn, Mark 
87388e2f98eSSalyzyn, Mark 	/*
87488e2f98eSSalyzyn, Mark 	 *	Check that the command queued to the controller
87588e2f98eSSalyzyn, Mark 	 */
87688e2f98eSSalyzyn, Mark 	if (status == -EINPROGRESS) {
87788e2f98eSSalyzyn, Mark 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
87888e2f98eSSalyzyn, Mark 		return 0;
87988e2f98eSSalyzyn, Mark 	}
88088e2f98eSSalyzyn, Mark 
88188e2f98eSSalyzyn, Mark 	printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
88288e2f98eSSalyzyn, Mark 	aac_fib_complete(cmd_fibcontext);
88388e2f98eSSalyzyn, Mark 	aac_fib_free(cmd_fibcontext);
88488e2f98eSSalyzyn, Mark 	return -1;
88588e2f98eSSalyzyn, Mark }
88688e2f98eSSalyzyn, Mark 
88788e2f98eSSalyzyn, Mark /* Function: setinqserial
88888e2f98eSSalyzyn, Mark  *
88988e2f98eSSalyzyn, Mark  * Arguments: [1] pointer to void [1] int
89088e2f98eSSalyzyn, Mark  *
89188e2f98eSSalyzyn, Mark  * Purpose: Sets SCSI Unit Serial number.
89288e2f98eSSalyzyn, Mark  *          This is a fake. We should read a proper
89388e2f98eSSalyzyn, Mark  *          serial number from the container. <SuSE>But
89488e2f98eSSalyzyn, Mark  *          without docs it's quite hard to do it :-)
89588e2f98eSSalyzyn, Mark  *          So this will have to do in the meantime.</SuSE>
89688e2f98eSSalyzyn, Mark  */
89788e2f98eSSalyzyn, Mark 
89888e2f98eSSalyzyn, Mark static int setinqserial(struct aac_dev *dev, void *data, int cid)
89988e2f98eSSalyzyn, Mark {
90088e2f98eSSalyzyn, Mark 	/*
90188e2f98eSSalyzyn, Mark 	 *	This breaks array migration.
90288e2f98eSSalyzyn, Mark 	 */
90388e2f98eSSalyzyn, Mark 	return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
90488e2f98eSSalyzyn, Mark 			le32_to_cpu(dev->adapter_info.serial[0]), cid);
90588e2f98eSSalyzyn, Mark }
90688e2f98eSSalyzyn, Mark 
9078e31e607SSalyzyn, Mark static inline void set_sense(struct sense_data *sense_data, u8 sense_key,
9088e31e607SSalyzyn, Mark 	u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer)
9091da177e4SLinus Torvalds {
9108e31e607SSalyzyn, Mark 	u8 *sense_buf = (u8 *)sense_data;
9118e31e607SSalyzyn, Mark 	/* Sense data valid, err code 70h */
9128e31e607SSalyzyn, Mark 	sense_buf[0] = 0x70; /* No info field */
9131da177e4SLinus Torvalds 	sense_buf[1] = 0;	/* Segment number, always zero */
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	sense_buf[2] = sense_key;	/* Sense key */
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds 	sense_buf[12] = sense_code;	/* Additional sense code */
9181da177e4SLinus Torvalds 	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */
9198e31e607SSalyzyn, Mark 
9201da177e4SLinus Torvalds 	if (sense_key == ILLEGAL_REQUEST) {
9218e31e607SSalyzyn, Mark 		sense_buf[7] = 10;	/* Additional sense length */
9221da177e4SLinus Torvalds 
9238e31e607SSalyzyn, Mark 		sense_buf[15] = bit_pointer;
9241da177e4SLinus Torvalds 		/* Illegal parameter is in the parameter block */
9251da177e4SLinus Torvalds 		if (sense_code == SENCODE_INVALID_CDB_FIELD)
9268e31e607SSalyzyn, Mark 			sense_buf[15] |= 0xc0;/* Std sense key specific field */
9271da177e4SLinus Torvalds 		/* Illegal parameter is in the CDB block */
9281da177e4SLinus Torvalds 		sense_buf[16] = field_pointer >> 8;	/* MSB */
9291da177e4SLinus Torvalds 		sense_buf[17] = field_pointer;		/* LSB */
9308e31e607SSalyzyn, Mark 	} else
9318e31e607SSalyzyn, Mark 		sense_buf[7] = 6;	/* Additional sense length */
9321da177e4SLinus Torvalds }
9331da177e4SLinus Torvalds 
934e8f32de5SMark Haverkamp static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
935e8f32de5SMark Haverkamp {
936e8f32de5SMark Haverkamp 	if (lba & 0xffffffff00000000LL) {
937e8f32de5SMark Haverkamp 		int cid = scmd_id(cmd);
938e8f32de5SMark Haverkamp 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
939e8f32de5SMark Haverkamp 		cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
940e8f32de5SMark Haverkamp 			SAM_STAT_CHECK_CONDITION;
9418e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
9428e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
9438e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
944e8f32de5SMark Haverkamp 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
9453ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
9463ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
947e8f32de5SMark Haverkamp 		cmd->scsi_done(cmd);
948e8f32de5SMark Haverkamp 		return 1;
949e8f32de5SMark Haverkamp 	}
950e8f32de5SMark Haverkamp 	return 0;
951e8f32de5SMark Haverkamp }
952e8f32de5SMark Haverkamp 
953e8f32de5SMark Haverkamp static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
954e8f32de5SMark Haverkamp {
955e8f32de5SMark Haverkamp 	return 0;
956e8f32de5SMark Haverkamp }
957e8f32de5SMark Haverkamp 
958e8f32de5SMark Haverkamp static void io_callback(void *context, struct fib * fibptr);
959e8f32de5SMark Haverkamp 
960e8f32de5SMark Haverkamp static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
961e8f32de5SMark Haverkamp {
962e8f32de5SMark Haverkamp 	u16 fibsize;
963e8f32de5SMark Haverkamp 	struct aac_raw_io *readcmd;
964e8f32de5SMark Haverkamp 	aac_fib_init(fib);
965e8f32de5SMark Haverkamp 	readcmd = (struct aac_raw_io *) fib_data(fib);
966e8f32de5SMark Haverkamp 	readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
967e8f32de5SMark Haverkamp 	readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
968e8f32de5SMark Haverkamp 	readcmd->count = cpu_to_le32(count<<9);
969e8f32de5SMark Haverkamp 	readcmd->cid = cpu_to_le16(scmd_id(cmd));
9709d399cc7SSalyzyn, Mark 	readcmd->flags = cpu_to_le16(IO_TYPE_READ);
971e8f32de5SMark Haverkamp 	readcmd->bpTotal = 0;
972e8f32de5SMark Haverkamp 	readcmd->bpComplete = 0;
973e8f32de5SMark Haverkamp 
974e8f32de5SMark Haverkamp 	aac_build_sgraw(cmd, &readcmd->sg);
975e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
976e8f32de5SMark Haverkamp 	BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
977e8f32de5SMark Haverkamp 	/*
978e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
979e8f32de5SMark Haverkamp 	 */
980e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerRawIo,
981e8f32de5SMark Haverkamp 			  fib,
982e8f32de5SMark Haverkamp 			  fibsize,
983e8f32de5SMark Haverkamp 			  FsaNormal,
984e8f32de5SMark Haverkamp 			  0, 1,
985e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
986e8f32de5SMark Haverkamp 			  (void *) cmd);
987e8f32de5SMark Haverkamp }
988e8f32de5SMark Haverkamp 
989e8f32de5SMark Haverkamp static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
990e8f32de5SMark Haverkamp {
991e8f32de5SMark Haverkamp 	u16 fibsize;
992e8f32de5SMark Haverkamp 	struct aac_read64 *readcmd;
993e8f32de5SMark Haverkamp 	aac_fib_init(fib);
994e8f32de5SMark Haverkamp 	readcmd = (struct aac_read64 *) fib_data(fib);
995e8f32de5SMark Haverkamp 	readcmd->command = cpu_to_le32(VM_CtHostRead64);
996e8f32de5SMark Haverkamp 	readcmd->cid = cpu_to_le16(scmd_id(cmd));
997e8f32de5SMark Haverkamp 	readcmd->sector_count = cpu_to_le16(count);
998e8f32de5SMark Haverkamp 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
999e8f32de5SMark Haverkamp 	readcmd->pad   = 0;
1000e8f32de5SMark Haverkamp 	readcmd->flags = 0;
1001e8f32de5SMark Haverkamp 
1002e8f32de5SMark Haverkamp 	aac_build_sg64(cmd, &readcmd->sg);
1003e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_read64) +
1004e8f32de5SMark Haverkamp 		((le32_to_cpu(readcmd->sg.count) - 1) *
1005e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1006e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1007e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1008e8f32de5SMark Haverkamp 	/*
1009e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1010e8f32de5SMark Haverkamp 	 */
1011e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand64,
1012e8f32de5SMark Haverkamp 			  fib,
1013e8f32de5SMark Haverkamp 			  fibsize,
1014e8f32de5SMark Haverkamp 			  FsaNormal,
1015e8f32de5SMark Haverkamp 			  0, 1,
1016e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1017e8f32de5SMark Haverkamp 			  (void *) cmd);
1018e8f32de5SMark Haverkamp }
1019e8f32de5SMark Haverkamp 
1020e8f32de5SMark Haverkamp static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
1021e8f32de5SMark Haverkamp {
1022e8f32de5SMark Haverkamp 	u16 fibsize;
1023e8f32de5SMark Haverkamp 	struct aac_read *readcmd;
1024e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1025e8f32de5SMark Haverkamp 	readcmd = (struct aac_read *) fib_data(fib);
1026e8f32de5SMark Haverkamp 	readcmd->command = cpu_to_le32(VM_CtBlockRead);
1027f3307f72SChristoph Hellwig 	readcmd->cid = cpu_to_le32(scmd_id(cmd));
1028e8f32de5SMark Haverkamp 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1029e8f32de5SMark Haverkamp 	readcmd->count = cpu_to_le32(count * 512);
1030e8f32de5SMark Haverkamp 
1031e8f32de5SMark Haverkamp 	aac_build_sg(cmd, &readcmd->sg);
1032e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_read) +
1033e8f32de5SMark Haverkamp 			((le32_to_cpu(readcmd->sg.count) - 1) *
1034e8f32de5SMark Haverkamp 			 sizeof (struct sgentry));
1035e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1036e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1037e8f32de5SMark Haverkamp 	/*
1038e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1039e8f32de5SMark Haverkamp 	 */
1040e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand,
1041e8f32de5SMark Haverkamp 			  fib,
1042e8f32de5SMark Haverkamp 			  fibsize,
1043e8f32de5SMark Haverkamp 			  FsaNormal,
1044e8f32de5SMark Haverkamp 			  0, 1,
1045e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1046e8f32de5SMark Haverkamp 			  (void *) cmd);
1047e8f32de5SMark Haverkamp }
1048e8f32de5SMark Haverkamp 
10499d399cc7SSalyzyn, Mark static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1050e8f32de5SMark Haverkamp {
1051e8f32de5SMark Haverkamp 	u16 fibsize;
1052e8f32de5SMark Haverkamp 	struct aac_raw_io *writecmd;
1053e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1054e8f32de5SMark Haverkamp 	writecmd = (struct aac_raw_io *) fib_data(fib);
1055e8f32de5SMark Haverkamp 	writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
1056e8f32de5SMark Haverkamp 	writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
1057e8f32de5SMark Haverkamp 	writecmd->count = cpu_to_le32(count<<9);
1058e8f32de5SMark Haverkamp 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
105995e852e1SSalyzyn, Mark 	writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
106095e852e1SSalyzyn, Mark 	  (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
10619d399cc7SSalyzyn, Mark 		cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
10629d399cc7SSalyzyn, Mark 		cpu_to_le16(IO_TYPE_WRITE);
1063e8f32de5SMark Haverkamp 	writecmd->bpTotal = 0;
1064e8f32de5SMark Haverkamp 	writecmd->bpComplete = 0;
1065e8f32de5SMark Haverkamp 
1066e8f32de5SMark Haverkamp 	aac_build_sgraw(cmd, &writecmd->sg);
1067e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
1068e8f32de5SMark Haverkamp 	BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
1069e8f32de5SMark Haverkamp 	/*
1070e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1071e8f32de5SMark Haverkamp 	 */
1072e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerRawIo,
1073e8f32de5SMark Haverkamp 			  fib,
1074e8f32de5SMark Haverkamp 			  fibsize,
1075e8f32de5SMark Haverkamp 			  FsaNormal,
1076e8f32de5SMark Haverkamp 			  0, 1,
1077e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1078e8f32de5SMark Haverkamp 			  (void *) cmd);
1079e8f32de5SMark Haverkamp }
1080e8f32de5SMark Haverkamp 
10819d399cc7SSalyzyn, Mark static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1082e8f32de5SMark Haverkamp {
1083e8f32de5SMark Haverkamp 	u16 fibsize;
1084e8f32de5SMark Haverkamp 	struct aac_write64 *writecmd;
1085e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1086e8f32de5SMark Haverkamp 	writecmd = (struct aac_write64 *) fib_data(fib);
1087e8f32de5SMark Haverkamp 	writecmd->command = cpu_to_le32(VM_CtHostWrite64);
1088e8f32de5SMark Haverkamp 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
1089e8f32de5SMark Haverkamp 	writecmd->sector_count = cpu_to_le16(count);
1090e8f32de5SMark Haverkamp 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1091e8f32de5SMark Haverkamp 	writecmd->pad	= 0;
1092e8f32de5SMark Haverkamp 	writecmd->flags	= 0;
1093e8f32de5SMark Haverkamp 
1094e8f32de5SMark Haverkamp 	aac_build_sg64(cmd, &writecmd->sg);
1095e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_write64) +
1096e8f32de5SMark Haverkamp 		((le32_to_cpu(writecmd->sg.count) - 1) *
1097e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1098e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1099e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1100e8f32de5SMark Haverkamp 	/*
1101e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1102e8f32de5SMark Haverkamp 	 */
1103e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand64,
1104e8f32de5SMark Haverkamp 			  fib,
1105e8f32de5SMark Haverkamp 			  fibsize,
1106e8f32de5SMark Haverkamp 			  FsaNormal,
1107e8f32de5SMark Haverkamp 			  0, 1,
1108e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1109e8f32de5SMark Haverkamp 			  (void *) cmd);
1110e8f32de5SMark Haverkamp }
1111e8f32de5SMark Haverkamp 
11129d399cc7SSalyzyn, Mark static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
1113e8f32de5SMark Haverkamp {
1114e8f32de5SMark Haverkamp 	u16 fibsize;
1115e8f32de5SMark Haverkamp 	struct aac_write *writecmd;
1116e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1117e8f32de5SMark Haverkamp 	writecmd = (struct aac_write *) fib_data(fib);
1118e8f32de5SMark Haverkamp 	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
1119f3307f72SChristoph Hellwig 	writecmd->cid = cpu_to_le32(scmd_id(cmd));
1120e8f32de5SMark Haverkamp 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
1121e8f32de5SMark Haverkamp 	writecmd->count = cpu_to_le32(count * 512);
1122e8f32de5SMark Haverkamp 	writecmd->sg.count = cpu_to_le32(1);
1123e8f32de5SMark Haverkamp 	/* ->stable is not used - it did mean which type of write */
1124e8f32de5SMark Haverkamp 
1125e8f32de5SMark Haverkamp 	aac_build_sg(cmd, &writecmd->sg);
1126e8f32de5SMark Haverkamp 	fibsize = sizeof(struct aac_write) +
1127e8f32de5SMark Haverkamp 		((le32_to_cpu(writecmd->sg.count) - 1) *
1128e8f32de5SMark Haverkamp 		 sizeof (struct sgentry));
1129e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1130e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1131e8f32de5SMark Haverkamp 	/*
1132e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1133e8f32de5SMark Haverkamp 	 */
1134e8f32de5SMark Haverkamp 	return aac_fib_send(ContainerCommand,
1135e8f32de5SMark Haverkamp 			  fib,
1136e8f32de5SMark Haverkamp 			  fibsize,
1137e8f32de5SMark Haverkamp 			  FsaNormal,
1138e8f32de5SMark Haverkamp 			  0, 1,
1139e8f32de5SMark Haverkamp 			  (fib_callback) io_callback,
1140e8f32de5SMark Haverkamp 			  (void *) cmd);
1141e8f32de5SMark Haverkamp }
1142e8f32de5SMark Haverkamp 
1143e8f32de5SMark Haverkamp static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd)
1144e8f32de5SMark Haverkamp {
1145e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd;
1146e8f32de5SMark Haverkamp 	u32 flag;
1147e8f32de5SMark Haverkamp 	u32 timeout;
1148e8f32de5SMark Haverkamp 
1149e8f32de5SMark Haverkamp 	aac_fib_init(fib);
1150e8f32de5SMark Haverkamp 	switch(cmd->sc_data_direction){
1151e8f32de5SMark Haverkamp 	case DMA_TO_DEVICE:
1152e8f32de5SMark Haverkamp 		flag = SRB_DataOut;
1153e8f32de5SMark Haverkamp 		break;
1154e8f32de5SMark Haverkamp 	case DMA_BIDIRECTIONAL:
1155e8f32de5SMark Haverkamp 		flag = SRB_DataIn | SRB_DataOut;
1156e8f32de5SMark Haverkamp 		break;
1157e8f32de5SMark Haverkamp 	case DMA_FROM_DEVICE:
1158e8f32de5SMark Haverkamp 		flag = SRB_DataIn;
1159e8f32de5SMark Haverkamp 		break;
1160e8f32de5SMark Haverkamp 	case DMA_NONE:
1161e8f32de5SMark Haverkamp 	default:	/* shuts up some versions of gcc */
1162e8f32de5SMark Haverkamp 		flag = SRB_NoDataXfer;
1163e8f32de5SMark Haverkamp 		break;
1164e8f32de5SMark Haverkamp 	}
1165e8f32de5SMark Haverkamp 
1166e8f32de5SMark Haverkamp 	srbcmd = (struct aac_srb*) fib_data(fib);
1167e8f32de5SMark Haverkamp 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
1168e8f32de5SMark Haverkamp 	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd)));
1169e8f32de5SMark Haverkamp 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
1170e8f32de5SMark Haverkamp 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
1171e8f32de5SMark Haverkamp 	srbcmd->flags    = cpu_to_le32(flag);
1172242f9dcbSJens Axboe 	timeout = cmd->request->timeout/HZ;
1173e8f32de5SMark Haverkamp 	if (timeout == 0)
1174e8f32de5SMark Haverkamp 		timeout = 1;
1175e8f32de5SMark Haverkamp 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
1176e8f32de5SMark Haverkamp 	srbcmd->retry_limit = 0; /* Obsolete parameter */
1177e8f32de5SMark Haverkamp 	srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len);
1178e8f32de5SMark Haverkamp 	return srbcmd;
1179e8f32de5SMark Haverkamp }
1180e8f32de5SMark Haverkamp 
1181e8f32de5SMark Haverkamp static void aac_srb_callback(void *context, struct fib * fibptr);
1182e8f32de5SMark Haverkamp 
1183e8f32de5SMark Haverkamp static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
1184e8f32de5SMark Haverkamp {
1185e8f32de5SMark Haverkamp 	u16 fibsize;
1186e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
1187e8f32de5SMark Haverkamp 
1188e8f32de5SMark Haverkamp 	aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg);
1189727eead6SFUJITA Tomonori 	srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
1190e8f32de5SMark Haverkamp 
1191e8f32de5SMark Haverkamp 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1192e8f32de5SMark Haverkamp 	memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
1193e8f32de5SMark Haverkamp 	/*
1194e8f32de5SMark Haverkamp 	 *	Build Scatter/Gather list
1195e8f32de5SMark Haverkamp 	 */
1196e8f32de5SMark Haverkamp 	fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
1197e8f32de5SMark Haverkamp 		((le32_to_cpu(srbcmd->sg.count) & 0xff) *
1198e8f32de5SMark Haverkamp 		 sizeof (struct sgentry64));
1199e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1200e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1201e8f32de5SMark Haverkamp 
1202e8f32de5SMark Haverkamp 	/*
1203e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1204e8f32de5SMark Haverkamp 	 */
1205e8f32de5SMark Haverkamp 	return aac_fib_send(ScsiPortCommand64, fib,
1206e8f32de5SMark Haverkamp 				fibsize, FsaNormal, 0, 1,
1207e8f32de5SMark Haverkamp 				  (fib_callback) aac_srb_callback,
1208e8f32de5SMark Haverkamp 				  (void *) cmd);
1209e8f32de5SMark Haverkamp }
1210e8f32de5SMark Haverkamp 
1211e8f32de5SMark Haverkamp static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
1212e8f32de5SMark Haverkamp {
1213e8f32de5SMark Haverkamp 	u16 fibsize;
1214e8f32de5SMark Haverkamp 	struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
1215e8f32de5SMark Haverkamp 
1216e8f32de5SMark Haverkamp 	aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg);
1217727eead6SFUJITA Tomonori 	srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
1218e8f32de5SMark Haverkamp 
1219e8f32de5SMark Haverkamp 	memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
1220e8f32de5SMark Haverkamp 	memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
1221e8f32de5SMark Haverkamp 	/*
1222e8f32de5SMark Haverkamp 	 *	Build Scatter/Gather list
1223e8f32de5SMark Haverkamp 	 */
1224e8f32de5SMark Haverkamp 	fibsize = sizeof (struct aac_srb) +
1225e8f32de5SMark Haverkamp 		(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
1226e8f32de5SMark Haverkamp 		 sizeof (struct sgentry));
1227e8f32de5SMark Haverkamp 	BUG_ON (fibsize > (fib->dev->max_fib_size -
1228e8f32de5SMark Haverkamp 				sizeof(struct aac_fibhdr)));
1229e8f32de5SMark Haverkamp 
1230e8f32de5SMark Haverkamp 	/*
1231e8f32de5SMark Haverkamp 	 *	Now send the Fib to the adapter
1232e8f32de5SMark Haverkamp 	 */
1233e8f32de5SMark Haverkamp 	return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1,
1234e8f32de5SMark Haverkamp 				  (fib_callback) aac_srb_callback, (void *) cmd);
1235e8f32de5SMark Haverkamp }
1236e8f32de5SMark Haverkamp 
123794cf6ba1SSalyzyn, Mark static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
123894cf6ba1SSalyzyn, Mark {
1239d8e96507SLeubner, Achim 	if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac &&
124094cf6ba1SSalyzyn, Mark 	    (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
124194cf6ba1SSalyzyn, Mark 		return FAILED;
124294cf6ba1SSalyzyn, Mark 	return aac_scsi_32(fib, cmd);
124394cf6ba1SSalyzyn, Mark }
124494cf6ba1SSalyzyn, Mark 
12451da177e4SLinus Torvalds int aac_get_adapter_info(struct aac_dev* dev)
12461da177e4SLinus Torvalds {
12471da177e4SLinus Torvalds 	struct fib* fibptr;
12481da177e4SLinus Torvalds 	int rcode;
12491da177e4SLinus Torvalds 	u32 tmp;
12507c00ffa3SMark Haverkamp  	struct aac_adapter_info *info;
125184971738SMark Haverkamp 	struct aac_bus_info *command;
125284971738SMark Haverkamp 	struct aac_bus_info_response *bus_info;
12537c00ffa3SMark Haverkamp  
1254bfb35aa8SMark Haverkamp 	if (!(fibptr = aac_fib_alloc(dev)))
12551da177e4SLinus Torvalds 		return -ENOMEM;
12561da177e4SLinus Torvalds 
1257bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
12581da177e4SLinus Torvalds 	info = (struct aac_adapter_info *) fib_data(fibptr);
12597c00ffa3SMark Haverkamp  	memset(info,0,sizeof(*info));
12601da177e4SLinus Torvalds 
1261bfb35aa8SMark Haverkamp 	rcode = aac_fib_send(RequestAdapterInfo,
12621da177e4SLinus Torvalds 			 fibptr,
12637c00ffa3SMark Haverkamp  			 sizeof(*info),
12641da177e4SLinus Torvalds 			 FsaNormal,
12659203344cSMark Haverkamp 			 -1, 1, /* First `interrupt' command uses special wait */
12661da177e4SLinus Torvalds 			 NULL,
12671da177e4SLinus Torvalds 			 NULL);
12681da177e4SLinus Torvalds 
12697c00ffa3SMark Haverkamp  	if (rcode < 0) {
1270cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		/* FIB should be freed only after
1271cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		 * getting the response from the F/W */
1272cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		if (rcode != -ERESTARTSYS) {
1273bfb35aa8SMark Haverkamp 			aac_fib_complete(fibptr);
1274bfb35aa8SMark Haverkamp 			aac_fib_free(fibptr);
1275cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		}
12767c00ffa3SMark Haverkamp  		return rcode;
12777c00ffa3SMark Haverkamp  	}
12787c00ffa3SMark Haverkamp  	memcpy(&dev->adapter_info, info, sizeof(*info));
12797c00ffa3SMark Haverkamp  
12807c00ffa3SMark Haverkamp  	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
128106a43d17SSalyzyn, Mark 		struct aac_supplement_adapter_info * sinfo;
12827c00ffa3SMark Haverkamp  
1283bfb35aa8SMark Haverkamp 		aac_fib_init(fibptr);
12847c00ffa3SMark Haverkamp  
128506a43d17SSalyzyn, Mark 		sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
12867c00ffa3SMark Haverkamp  
128706a43d17SSalyzyn, Mark 		memset(sinfo,0,sizeof(*sinfo));
12887c00ffa3SMark Haverkamp  
1289bfb35aa8SMark Haverkamp 		rcode = aac_fib_send(RequestSupplementAdapterInfo,
12907c00ffa3SMark Haverkamp  				 fibptr,
129106a43d17SSalyzyn, Mark 				 sizeof(*sinfo),
12927c00ffa3SMark Haverkamp  				 FsaNormal,
12937c00ffa3SMark Haverkamp  				 1, 1,
12947c00ffa3SMark Haverkamp  				 NULL,
12957c00ffa3SMark Haverkamp  				 NULL);
12967c00ffa3SMark Haverkamp  
12977c00ffa3SMark Haverkamp  		if (rcode >= 0)
129806a43d17SSalyzyn, Mark 			memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
1299cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		if (rcode == -ERESTARTSYS) {
1300cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			fibptr = aac_fib_alloc(dev);
1301cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 			if (!fibptr)
1302cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 				return -ENOMEM;
1303cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		}
1304cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
13057c00ffa3SMark Haverkamp  	}
13061da177e4SLinus Torvalds 
130784971738SMark Haverkamp 
130884971738SMark Haverkamp 	/*
130984971738SMark Haverkamp 	 * GetBusInfo
131084971738SMark Haverkamp 	 */
131184971738SMark Haverkamp 
1312bfb35aa8SMark Haverkamp 	aac_fib_init(fibptr);
131384971738SMark Haverkamp 
131484971738SMark Haverkamp 	bus_info = (struct aac_bus_info_response *) fib_data(fibptr);
131584971738SMark Haverkamp 
131684971738SMark Haverkamp 	memset(bus_info, 0, sizeof(*bus_info));
131784971738SMark Haverkamp 
131884971738SMark Haverkamp 	command = (struct aac_bus_info *)bus_info;
131984971738SMark Haverkamp 
132084971738SMark Haverkamp 	command->Command = cpu_to_le32(VM_Ioctl);
132184971738SMark Haverkamp 	command->ObjType = cpu_to_le32(FT_DRIVE);
132284971738SMark Haverkamp 	command->MethodId = cpu_to_le32(1);
132384971738SMark Haverkamp 	command->CtlCmd = cpu_to_le32(GetBusInfo);
132484971738SMark Haverkamp 
1325bfb35aa8SMark Haverkamp 	rcode = aac_fib_send(ContainerCommand,
132684971738SMark Haverkamp 			 fibptr,
132784971738SMark Haverkamp 			 sizeof (*bus_info),
132884971738SMark Haverkamp 			 FsaNormal,
132984971738SMark Haverkamp 			 1, 1,
133084971738SMark Haverkamp 			 NULL, NULL);
133184971738SMark Haverkamp 
133294cf6ba1SSalyzyn, Mark 	/* reasoned default */
133394cf6ba1SSalyzyn, Mark 	dev->maximum_num_physicals = 16;
133484971738SMark Haverkamp 	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
133584971738SMark Haverkamp 		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
133684971738SMark Haverkamp 		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
133784971738SMark Haverkamp 	}
133884971738SMark Haverkamp 
13398c867b25SMark Haverkamp 	if (!dev->in_reset) {
134024f02e1dSSalyzyn, Mark 		char buffer[16];
13411da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
13427c00ffa3SMark Haverkamp  		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
13431da177e4SLinus Torvalds 			dev->name,
13441da177e4SLinus Torvalds 			dev->id,
13451da177e4SLinus Torvalds 			tmp>>24,
13461da177e4SLinus Torvalds 			(tmp>>16)&0xff,
13471da177e4SLinus Torvalds 			tmp&0xff,
13487c00ffa3SMark Haverkamp  			le32_to_cpu(dev->adapter_info.kernelbuild),
13497c00ffa3SMark Haverkamp  			(int)sizeof(dev->supplement_adapter_info.BuildDate),
13507c00ffa3SMark Haverkamp  			dev->supplement_adapter_info.BuildDate);
13511da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.monitorrev);
13521da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
13531da177e4SLinus Torvalds 			dev->name, dev->id,
13541da177e4SLinus Torvalds 			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
13551da177e4SLinus Torvalds 			le32_to_cpu(dev->adapter_info.monitorbuild));
13561da177e4SLinus Torvalds 		tmp = le32_to_cpu(dev->adapter_info.biosrev);
13571da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
13581da177e4SLinus Torvalds 			dev->name, dev->id,
13591da177e4SLinus Torvalds 			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
13601da177e4SLinus Torvalds 			le32_to_cpu(dev->adapter_info.biosbuild));
136124f02e1dSSalyzyn, Mark 		buffer[0] = '\0';
1362ee959b00STony Jones 		if (aac_get_serial_number(
136324f02e1dSSalyzyn, Mark 		  shost_to_class(dev->scsi_host_ptr), buffer))
136424f02e1dSSalyzyn, Mark 			printk(KERN_INFO "%s%d: serial %s",
136524f02e1dSSalyzyn, Mark 			  dev->name, dev->id, buffer);
1366a45c863fSSalyzyn, Mark 		if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
1367a45c863fSSalyzyn, Mark 			printk(KERN_INFO "%s%d: TSID %.*s\n",
1368a45c863fSSalyzyn, Mark 			  dev->name, dev->id,
1369a45c863fSSalyzyn, Mark 			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
1370a45c863fSSalyzyn, Mark 			  dev->supplement_adapter_info.VpdInfo.Tsid);
1371a45c863fSSalyzyn, Mark 		}
13722f7ecc55SSalyzyn, Mark 		if (!aac_check_reset || ((aac_check_reset == 1) &&
137329c97684SSalyzyn, Mark 		  (dev->supplement_adapter_info.SupportedOptions2 &
1374a3940da5SSalyzyn, Mark 		  AAC_OPTION_IGNORE_RESET))) {
137529c97684SSalyzyn, Mark 			printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
137629c97684SSalyzyn, Mark 			  dev->name, dev->id);
137729c97684SSalyzyn, Mark 		}
13788c867b25SMark Haverkamp 	}
13791da177e4SLinus Torvalds 
138095e852e1SSalyzyn, Mark 	dev->cache_protected = 0;
1381cb1042f2SSalyzyn, Mark 	dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
1382cb1042f2SSalyzyn, Mark 		AAC_FEATURE_JBOD) != 0);
13831da177e4SLinus Torvalds 	dev->nondasd_support = 0;
13841da177e4SLinus Torvalds 	dev->raid_scsi_mode = 0;
138595e852e1SSalyzyn, Mark 	if(dev->adapter_info.options & AAC_OPT_NONDASD)
13861da177e4SLinus Torvalds 		dev->nondasd_support = 1;
13871da177e4SLinus Torvalds 
13881da177e4SLinus Torvalds 	/*
13891da177e4SLinus Torvalds 	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
13901da177e4SLinus Torvalds 	 * in RAID/SCSI mode, set the flag. For now if in this mode we will
13911da177e4SLinus Torvalds 	 * force nondasd support on. If we decide to allow the non-dasd flag
13921da177e4SLinus Torvalds 	 * additional changes changes will have to be made to support
13931da177e4SLinus Torvalds 	 * RAID/SCSI.  the function aac_scsi_cmd in this module will have to be
13941da177e4SLinus Torvalds 	 * changed to support the new dev->raid_scsi_mode flag instead of
13951da177e4SLinus Torvalds 	 * leaching off of the dev->nondasd_support flag. Also in linit.c the
13961da177e4SLinus Torvalds 	 * function aac_detect will have to be modified where it sets up the
13971da177e4SLinus Torvalds 	 * max number of channels based on the aac->nondasd_support flag only.
13981da177e4SLinus Torvalds 	 */
13991da177e4SLinus Torvalds 	if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
14001da177e4SLinus Torvalds 	    (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
14011da177e4SLinus Torvalds 		dev->nondasd_support = 1;
14021da177e4SLinus Torvalds 		dev->raid_scsi_mode = 1;
14031da177e4SLinus Torvalds 	}
14041da177e4SLinus Torvalds 	if (dev->raid_scsi_mode != 0)
14051da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
14061da177e4SLinus Torvalds 				dev->name, dev->id);
14071da177e4SLinus Torvalds 
140895e852e1SSalyzyn, Mark 	if (nondasd != -1)
14091da177e4SLinus Torvalds 		dev->nondasd_support = (nondasd!=0);
14102f7ecc55SSalyzyn, Mark 	if (dev->nondasd_support && !dev->in_reset)
14111da177e4SLinus Torvalds 		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
14121da177e4SLinus Torvalds 
1413e930438cSYang Hongyang 	if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32))
1414d8e96507SLeubner, Achim 		dev->needs_dac = 1;
14151da177e4SLinus Torvalds 	dev->dac_support = 0;
1416d8e96507SLeubner, Achim 	if ((sizeof(dma_addr_t) > 4) && dev->needs_dac &&
1417d8e96507SLeubner, Achim 	    (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) {
14182f7ecc55SSalyzyn, Mark 		if (!dev->in_reset)
14192f7ecc55SSalyzyn, Mark 			printk(KERN_INFO "%s%d: 64bit support enabled.\n",
14202f7ecc55SSalyzyn, Mark 				dev->name, dev->id);
14211da177e4SLinus Torvalds 		dev->dac_support = 1;
14221da177e4SLinus Torvalds 	}
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 	if(dacmode != -1) {
14251da177e4SLinus Torvalds 		dev->dac_support = (dacmode!=0);
14261da177e4SLinus Torvalds 	}
1427d8e96507SLeubner, Achim 
1428d8e96507SLeubner, Achim 	/* avoid problems with AAC_QUIRK_SCSI_32 controllers */
1429d8e96507SLeubner, Achim 	if (dev->dac_support &&	(aac_get_driver_ident(dev->cardtype)->quirks
1430d8e96507SLeubner, Achim 		& AAC_QUIRK_SCSI_32)) {
1431d8e96507SLeubner, Achim 		dev->nondasd_support = 0;
1432d8e96507SLeubner, Achim 		dev->jbod = 0;
1433d8e96507SLeubner, Achim 		expose_physicals = 0;
1434d8e96507SLeubner, Achim 	}
1435d8e96507SLeubner, Achim 
14361da177e4SLinus Torvalds 	if(dev->dac_support != 0) {
14376a35528aSYang Hongyang 		if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) &&
14386a35528aSYang Hongyang 			!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
14392f7ecc55SSalyzyn, Mark 			if (!dev->in_reset)
14401da177e4SLinus Torvalds 				printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
14411da177e4SLinus Torvalds 					dev->name, dev->id);
1442284901a9SYang Hongyang 		} else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) &&
1443284901a9SYang Hongyang 			!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) {
14441da177e4SLinus Torvalds 			printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
14451da177e4SLinus Torvalds 				dev->name, dev->id);
14461da177e4SLinus Torvalds 			dev->dac_support = 0;
14471da177e4SLinus Torvalds 		} else {
14481da177e4SLinus Torvalds 			printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
14491da177e4SLinus Torvalds 				dev->name, dev->id);
14501da177e4SLinus Torvalds 			rcode = -ENOMEM;
14511da177e4SLinus Torvalds 		}
14521da177e4SLinus Torvalds 	}
14537c00ffa3SMark Haverkamp  	/*
1454e8f32de5SMark Haverkamp 	 * Deal with configuring for the individualized limits of each packet
1455e8f32de5SMark Haverkamp 	 * interface.
14567c00ffa3SMark Haverkamp  	 */
1457e8f32de5SMark Haverkamp 	dev->a_ops.adapter_scsi = (dev->dac_support)
145894cf6ba1SSalyzyn, Mark 	  ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
145994cf6ba1SSalyzyn, Mark 				? aac_scsi_32_64
146094cf6ba1SSalyzyn, Mark 				: aac_scsi_64)
1461e8f32de5SMark Haverkamp 				: aac_scsi_32;
1462e8f32de5SMark Haverkamp 	if (dev->raw_io_interface) {
1463e8f32de5SMark Haverkamp 		dev->a_ops.adapter_bounds = (dev->raw_io_64)
1464e8f32de5SMark Haverkamp 					? aac_bounds_64
1465e8f32de5SMark Haverkamp 					: aac_bounds_32;
1466e8f32de5SMark Haverkamp 		dev->a_ops.adapter_read = aac_read_raw_io;
1467e8f32de5SMark Haverkamp 		dev->a_ops.adapter_write = aac_write_raw_io;
1468e8f32de5SMark Haverkamp 	} else {
1469e8f32de5SMark Haverkamp 		dev->a_ops.adapter_bounds = aac_bounds_32;
14707c00ffa3SMark Haverkamp  		dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
14717c00ffa3SMark Haverkamp  			sizeof(struct aac_fibhdr) -
147263a70eeaSMark Haverkamp 			sizeof(struct aac_write) + sizeof(struct sgentry)) /
147363a70eeaSMark Haverkamp 				sizeof(struct sgentry);
14747c00ffa3SMark Haverkamp  		if (dev->dac_support) {
1475e8f32de5SMark Haverkamp 			dev->a_ops.adapter_read = aac_read_block64;
1476e8f32de5SMark Haverkamp 			dev->a_ops.adapter_write = aac_write_block64;
14777c00ffa3SMark Haverkamp  			/*
14787c00ffa3SMark Haverkamp  			 * 38 scatter gather elements
14797c00ffa3SMark Haverkamp  			 */
14807c00ffa3SMark Haverkamp  			dev->scsi_host_ptr->sg_tablesize =
14817c00ffa3SMark Haverkamp  				(dev->max_fib_size -
14827c00ffa3SMark Haverkamp  				sizeof(struct aac_fibhdr) -
14837c00ffa3SMark Haverkamp  				sizeof(struct aac_write64) +
148463a70eeaSMark Haverkamp 				sizeof(struct sgentry64)) /
148563a70eeaSMark Haverkamp 					sizeof(struct sgentry64);
1486e8f32de5SMark Haverkamp 		} else {
1487e8f32de5SMark Haverkamp 			dev->a_ops.adapter_read = aac_read_block;
1488e8f32de5SMark Haverkamp 			dev->a_ops.adapter_write = aac_write_block;
14897c00ffa3SMark Haverkamp  		}
14907c00ffa3SMark Haverkamp  		dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
1491e8b12f0fSMahesh Rajashekhara 		if (dev->adapter_info.options & AAC_OPT_NEW_COMM_TYPE1)
1492e8b12f0fSMahesh Rajashekhara 			dev->adapter_info.options |= AAC_OPT_NEW_COMM;
14937c00ffa3SMark Haverkamp  		if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
14947c00ffa3SMark Haverkamp  			/*
14957c00ffa3SMark Haverkamp  			 * Worst case size that could cause sg overflow when
14967c00ffa3SMark Haverkamp  			 * we break up SG elements that are larger than 64KB.
14977c00ffa3SMark Haverkamp  			 * Would be nice if we could tell the SCSI layer what
14987c00ffa3SMark Haverkamp  			 * the maximum SG element size can be. Worst case is
14997c00ffa3SMark Haverkamp  			 * (sg_tablesize-1) 4KB elements with one 64KB
15007c00ffa3SMark Haverkamp  			 * element.
15017c00ffa3SMark Haverkamp  			 *	32bit -> 468 or 238KB	64bit -> 424 or 212KB
15027c00ffa3SMark Haverkamp  			 */
15037c00ffa3SMark Haverkamp  			dev->scsi_host_ptr->max_sectors =
15047c00ffa3SMark Haverkamp  			  (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
15057c00ffa3SMark Haverkamp  		}
15060e68c003SMark Haverkamp 	}
1507cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	/* FIB should be freed only after getting the response from the F/W */
1508cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	if (rcode != -ERESTARTSYS) {
1509bfb35aa8SMark Haverkamp 		aac_fib_complete(fibptr);
1510bfb35aa8SMark Haverkamp 		aac_fib_free(fibptr);
1511cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 	}
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds 	return rcode;
15141da177e4SLinus Torvalds }
15151da177e4SLinus Torvalds 
15161da177e4SLinus Torvalds 
1517e53cb35aSMark Haverkamp static void io_callback(void *context, struct fib * fibptr)
15181da177e4SLinus Torvalds {
15191da177e4SLinus Torvalds 	struct aac_dev *dev;
15201da177e4SLinus Torvalds 	struct aac_read_reply *readreply;
15211da177e4SLinus Torvalds 	struct scsi_cmnd *scsicmd;
15221da177e4SLinus Torvalds 	u32 cid;
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
15251da177e4SLinus Torvalds 
152603d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
152703d44337SMark Haverkamp 		return;
152803d44337SMark Haverkamp 
15291a655040SSalyzyn, Mark 	dev = fibptr->dev;
1530e5718774SMark Haverkamp 	cid = scmd_id(scsicmd);
15311da177e4SLinus Torvalds 
15327a8cf29dSMark Haverkamp 	if (nblank(dprintk(x))) {
15337a8cf29dSMark Haverkamp 		u64 lba;
15347a8cf29dSMark Haverkamp 		switch (scsicmd->cmnd[0]) {
15357a8cf29dSMark Haverkamp 		case WRITE_6:
15367a8cf29dSMark Haverkamp 		case READ_6:
15377a8cf29dSMark Haverkamp 			lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
15387a8cf29dSMark Haverkamp 			    (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
15397a8cf29dSMark Haverkamp 			break;
15407a8cf29dSMark Haverkamp 		case WRITE_16:
15417a8cf29dSMark Haverkamp 		case READ_16:
15427a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 56) |
15437a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[3] << 48) |
15447a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[4] << 40) |
15457a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[5] << 32) |
15467a8cf29dSMark Haverkamp 			      ((u64)scsicmd->cmnd[6] << 24) |
15477a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[7] << 16) |
15487a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
15497a8cf29dSMark Haverkamp 			break;
15507a8cf29dSMark Haverkamp 		case WRITE_12:
15517a8cf29dSMark Haverkamp 		case READ_12:
15527a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 24) |
15537a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[3] << 16) |
15547a8cf29dSMark Haverkamp 			      (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
15557a8cf29dSMark Haverkamp 			break;
15567a8cf29dSMark Haverkamp 		default:
15577a8cf29dSMark Haverkamp 			lba = ((u64)scsicmd->cmnd[2] << 24) |
15587a8cf29dSMark Haverkamp 			       (scsicmd->cmnd[3] << 16) |
15597a8cf29dSMark Haverkamp 			       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
15607a8cf29dSMark Haverkamp 			break;
15617a8cf29dSMark Haverkamp 		}
15627a8cf29dSMark Haverkamp 		printk(KERN_DEBUG
15637a8cf29dSMark Haverkamp 		  "io_callback[cpu %d]: lba = %llu, t = %ld.\n",
15647a8cf29dSMark Haverkamp 		  smp_processor_id(), (unsigned long long)lba, jiffies);
15657a8cf29dSMark Haverkamp 	}
15661da177e4SLinus Torvalds 
1567125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
15681da177e4SLinus Torvalds 
1569727eead6SFUJITA Tomonori 	scsi_dma_unmap(scsicmd);
1570727eead6SFUJITA Tomonori 
15711da177e4SLinus Torvalds 	readreply = (struct aac_read_reply *)fib_data(fibptr);
1572655d722cSMark Salyzyn 	switch (le32_to_cpu(readreply->status)) {
1573655d722cSMark Salyzyn 	case ST_OK:
1574655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1575655d722cSMark Salyzyn 			SAM_STAT_GOOD;
1576655d722cSMark Salyzyn 		dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
1577655d722cSMark Salyzyn 		break;
1578655d722cSMark Salyzyn 	case ST_NOT_READY:
1579655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1580655d722cSMark Salyzyn 			SAM_STAT_CHECK_CONDITION;
1581655d722cSMark Salyzyn 		set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
1582655d722cSMark Salyzyn 		  SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
1583655d722cSMark Salyzyn 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
1584655d722cSMark Salyzyn 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
1585655d722cSMark Salyzyn 			     SCSI_SENSE_BUFFERSIZE));
1586655d722cSMark Salyzyn 		break;
1587655d722cSMark Salyzyn 	default:
15887c00ffa3SMark Haverkamp  #ifdef AAC_DETAILED_STATUS_INFO
1589e53cb35aSMark Haverkamp 		printk(KERN_WARNING "io_callback: io failed, status = %d\n",
15901da177e4SLinus Torvalds 		  le32_to_cpu(readreply->status));
15917c00ffa3SMark Haverkamp  #endif
1592655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1593655d722cSMark Salyzyn 			SAM_STAT_CHECK_CONDITION;
15948e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
15958e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
15968e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
15971da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
15983ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
15993ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
1600655d722cSMark Salyzyn 		break;
16011da177e4SLinus Torvalds 	}
1602bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
1603bfb35aa8SMark Haverkamp 	aac_fib_free(fibptr);
16041da177e4SLinus Torvalds 
16058e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
16061da177e4SLinus Torvalds }
16071da177e4SLinus Torvalds 
16089e7c349cSMark Haverkamp static int aac_read(struct scsi_cmnd * scsicmd)
16091da177e4SLinus Torvalds {
16107a8cf29dSMark Haverkamp 	u64 lba;
16111da177e4SLinus Torvalds 	u32 count;
16121da177e4SLinus Torvalds 	int status;
16131da177e4SLinus Torvalds 	struct aac_dev *dev;
16141da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
1615da3cc679SRajashekhara, Mahesh 	int cid;
16161da177e4SLinus Torvalds 
16171da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
16181da177e4SLinus Torvalds 	/*
16191da177e4SLinus Torvalds 	 *	Get block address and transfer length
16201da177e4SLinus Torvalds 	 */
16217a8cf29dSMark Haverkamp 	switch (scsicmd->cmnd[0]) {
16227a8cf29dSMark Haverkamp 	case READ_6:
16239e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
16241da177e4SLinus Torvalds 
16257a8cf29dSMark Haverkamp 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
16267a8cf29dSMark Haverkamp 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
16271da177e4SLinus Torvalds 		count = scsicmd->cmnd[4];
16281da177e4SLinus Torvalds 
16291da177e4SLinus Torvalds 		if (count == 0)
16301da177e4SLinus Torvalds 			count = 256;
16317a8cf29dSMark Haverkamp 		break;
16327a8cf29dSMark Haverkamp 	case READ_16:
16339e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
16347a8cf29dSMark Haverkamp 
16357a8cf29dSMark Haverkamp 		lba =	((u64)scsicmd->cmnd[2] << 56) |
16367a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[3] << 48) |
16377a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[4] << 40) |
16387a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[5] << 32) |
16397a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[6] << 24) |
16407a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
16417a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
16427a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[10] << 24) |
16437a8cf29dSMark Haverkamp 			(scsicmd->cmnd[11] << 16) |
16447a8cf29dSMark Haverkamp 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
16457a8cf29dSMark Haverkamp 		break;
16467a8cf29dSMark Haverkamp 	case READ_12:
16479e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
16487a8cf29dSMark Haverkamp 
16497a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) |
16507a8cf29dSMark Haverkamp 			(scsicmd->cmnd[3] << 16) |
16517a8cf29dSMark Haverkamp 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
16527a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[6] << 24) |
16537a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
16547a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
16557a8cf29dSMark Haverkamp 		break;
16567a8cf29dSMark Haverkamp 	default:
16579e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
16581da177e4SLinus Torvalds 
16597a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) |
16607a8cf29dSMark Haverkamp 			(scsicmd->cmnd[3] << 16) |
16617a8cf29dSMark Haverkamp 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
16621da177e4SLinus Torvalds 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
16637a8cf29dSMark Haverkamp 		break;
16641da177e4SLinus Torvalds 	}
1665da3cc679SRajashekhara, Mahesh 
1666da3cc679SRajashekhara, Mahesh 	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
1667da3cc679SRajashekhara, Mahesh 		cid = scmd_id(scsicmd);
1668da3cc679SRajashekhara, Mahesh 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
1669da3cc679SRajashekhara, Mahesh 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1670da3cc679SRajashekhara, Mahesh 			SAM_STAT_CHECK_CONDITION;
1671da3cc679SRajashekhara, Mahesh 		set_sense(&dev->fsa_dev[cid].sense_data,
1672da3cc679SRajashekhara, Mahesh 			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
1673da3cc679SRajashekhara, Mahesh 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
1674da3cc679SRajashekhara, Mahesh 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
1675da3cc679SRajashekhara, Mahesh 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
1676da3cc679SRajashekhara, Mahesh 			     SCSI_SENSE_BUFFERSIZE));
1677da3cc679SRajashekhara, Mahesh 		scsicmd->scsi_done(scsicmd);
1678da3cc679SRajashekhara, Mahesh 		return 1;
1679da3cc679SRajashekhara, Mahesh 	}
1680da3cc679SRajashekhara, Mahesh 
16817a8cf29dSMark Haverkamp 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
16827c00ffa3SMark Haverkamp  	  smp_processor_id(), (unsigned long long)lba, jiffies));
1683e8f32de5SMark Haverkamp 	if (aac_adapter_bounds(dev,scsicmd,lba))
16847a8cf29dSMark Haverkamp 		return 0;
16851da177e4SLinus Torvalds 	/*
16861da177e4SLinus Torvalds 	 *	Alocate and initialize a Fib
16871da177e4SLinus Torvalds 	 */
1688bfb35aa8SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
1689cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		printk(KERN_WARNING "aac_read: fib allocation failed\n");
16901da177e4SLinus Torvalds 		return -1;
16911da177e4SLinus Torvalds 	}
16921da177e4SLinus Torvalds 
1693e8f32de5SMark Haverkamp 	status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
16941da177e4SLinus Torvalds 
16951da177e4SLinus Torvalds 	/*
16961da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
16971da177e4SLinus Torvalds 	 */
169877d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
169977d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
17001da177e4SLinus Torvalds 		return 0;
170177d644d4SMark Haverkamp 	}
17021da177e4SLinus Torvalds 
1703bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
17041da177e4SLinus Torvalds 	/*
17051da177e4SLinus Torvalds 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
17061da177e4SLinus Torvalds 	 */
17071da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
17088e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
1709bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
1710bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
17111da177e4SLinus Torvalds 	return 0;
17121da177e4SLinus Torvalds }
17131da177e4SLinus Torvalds 
17149e7c349cSMark Haverkamp static int aac_write(struct scsi_cmnd * scsicmd)
17151da177e4SLinus Torvalds {
17167a8cf29dSMark Haverkamp 	u64 lba;
17171da177e4SLinus Torvalds 	u32 count;
17189d399cc7SSalyzyn, Mark 	int fua;
17191da177e4SLinus Torvalds 	int status;
17201da177e4SLinus Torvalds 	struct aac_dev *dev;
17211da177e4SLinus Torvalds 	struct fib * cmd_fibcontext;
1722da3cc679SRajashekhara, Mahesh 	int cid;
17231da177e4SLinus Torvalds 
17241da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
17251da177e4SLinus Torvalds 	/*
17261da177e4SLinus Torvalds 	 *	Get block address and transfer length
17271da177e4SLinus Torvalds 	 */
17281da177e4SLinus Torvalds 	if (scsicmd->cmnd[0] == WRITE_6)	/* 6 byte command */
17291da177e4SLinus Torvalds 	{
17301da177e4SLinus Torvalds 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
17311da177e4SLinus Torvalds 		count = scsicmd->cmnd[4];
17321da177e4SLinus Torvalds 		if (count == 0)
17331da177e4SLinus Torvalds 			count = 256;
17349d399cc7SSalyzyn, Mark 		fua = 0;
17357a8cf29dSMark Haverkamp 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
17369e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
17377a8cf29dSMark Haverkamp 
17387a8cf29dSMark Haverkamp 		lba =	((u64)scsicmd->cmnd[2] << 56) |
17397a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[3] << 48) |
17407a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[4] << 40) |
17417a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[5] << 32) |
17427a8cf29dSMark Haverkamp 			((u64)scsicmd->cmnd[6] << 24) |
17437a8cf29dSMark Haverkamp 			(scsicmd->cmnd[7] << 16) |
17447a8cf29dSMark Haverkamp 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
17457a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
17467a8cf29dSMark Haverkamp 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
17479d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
17487a8cf29dSMark Haverkamp 	} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
17499e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
17507a8cf29dSMark Haverkamp 
17517a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
17527a8cf29dSMark Haverkamp 		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
17537a8cf29dSMark Haverkamp 		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
17547a8cf29dSMark Haverkamp 		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
17559d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
17561da177e4SLinus Torvalds 	} else {
17579e7c349cSMark Haverkamp 		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
17587a8cf29dSMark Haverkamp 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
17591da177e4SLinus Torvalds 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
17609d399cc7SSalyzyn, Mark 		fua = scsicmd->cmnd[1] & 0x8;
17611da177e4SLinus Torvalds 	}
1762da3cc679SRajashekhara, Mahesh 
1763da3cc679SRajashekhara, Mahesh 	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
1764da3cc679SRajashekhara, Mahesh 		cid = scmd_id(scsicmd);
1765da3cc679SRajashekhara, Mahesh 		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
1766da3cc679SRajashekhara, Mahesh 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
1767da3cc679SRajashekhara, Mahesh 			SAM_STAT_CHECK_CONDITION;
1768da3cc679SRajashekhara, Mahesh 		set_sense(&dev->fsa_dev[cid].sense_data,
1769da3cc679SRajashekhara, Mahesh 			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
1770da3cc679SRajashekhara, Mahesh 			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
1771da3cc679SRajashekhara, Mahesh 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
1772da3cc679SRajashekhara, Mahesh 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
1773da3cc679SRajashekhara, Mahesh 			     SCSI_SENSE_BUFFERSIZE));
1774da3cc679SRajashekhara, Mahesh 		scsicmd->scsi_done(scsicmd);
1775da3cc679SRajashekhara, Mahesh 		return 1;
1776da3cc679SRajashekhara, Mahesh 	}
1777da3cc679SRajashekhara, Mahesh 
17787a8cf29dSMark Haverkamp 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
17791da177e4SLinus Torvalds 	  smp_processor_id(), (unsigned long long)lba, jiffies));
1780e8f32de5SMark Haverkamp 	if (aac_adapter_bounds(dev,scsicmd,lba))
17817a8cf29dSMark Haverkamp 		return 0;
17821da177e4SLinus Torvalds 	/*
17831da177e4SLinus Torvalds 	 *	Allocate and initialize a Fib then setup a BlockWrite command
17841da177e4SLinus Torvalds 	 */
1785bfb35aa8SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
1786cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		/* FIB temporarily unavailable,not catastrophic failure */
1787cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 
1788cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		/* scsicmd->result = DID_ERROR << 16;
1789cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		 * scsicmd->scsi_done(scsicmd);
1790cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		 * return 0;
1791cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		 */
1792cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		printk(KERN_WARNING "aac_write: fib allocation failed\n");
1793cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 		return -1;
17941da177e4SLinus Torvalds 	}
17951da177e4SLinus Torvalds 
17969d399cc7SSalyzyn, Mark 	status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
17971da177e4SLinus Torvalds 
17981da177e4SLinus Torvalds 	/*
17991da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
18001da177e4SLinus Torvalds 	 */
180177d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
180277d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
18031da177e4SLinus Torvalds 		return 0;
18041da177e4SLinus Torvalds 	}
18051da177e4SLinus Torvalds 
1806bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
18071da177e4SLinus Torvalds 	/*
18081da177e4SLinus Torvalds 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
18091da177e4SLinus Torvalds 	 */
18101da177e4SLinus Torvalds 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
18118e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
18121da177e4SLinus Torvalds 
1813bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
1814bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
18151da177e4SLinus Torvalds 	return 0;
18161da177e4SLinus Torvalds }
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds static void synchronize_callback(void *context, struct fib *fibptr)
18191da177e4SLinus Torvalds {
18201da177e4SLinus Torvalds 	struct aac_synchronize_reply *synchronizereply;
18211da177e4SLinus Torvalds 	struct scsi_cmnd *cmd;
18221da177e4SLinus Torvalds 
18231da177e4SLinus Torvalds 	cmd = context;
18241da177e4SLinus Torvalds 
182503d44337SMark Haverkamp 	if (!aac_valid_context(cmd, fibptr))
182603d44337SMark Haverkamp 		return;
182703d44337SMark Haverkamp 
18281da177e4SLinus Torvalds 	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
18291da177e4SLinus Torvalds 				smp_processor_id(), jiffies));
18301da177e4SLinus Torvalds 	BUG_ON(fibptr == NULL);
18311da177e4SLinus Torvalds 
18321da177e4SLinus Torvalds 
18331da177e4SLinus Torvalds 	synchronizereply = fib_data(fibptr);
18341da177e4SLinus Torvalds 	if (le32_to_cpu(synchronizereply->status) == CT_OK)
18351da177e4SLinus Torvalds 		cmd->result = DID_OK << 16 |
18361da177e4SLinus Torvalds 			COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
18371da177e4SLinus Torvalds 	else {
18381da177e4SLinus Torvalds 		struct scsi_device *sdev = cmd->device;
18391a655040SSalyzyn, Mark 		struct aac_dev *dev = fibptr->dev;
1840e5718774SMark Haverkamp 		u32 cid = sdev_id(sdev);
18411da177e4SLinus Torvalds 		printk(KERN_WARNING
18421da177e4SLinus Torvalds 		     "synchronize_callback: synchronize failed, status = %d\n",
18431da177e4SLinus Torvalds 		     le32_to_cpu(synchronizereply->status));
18441da177e4SLinus Torvalds 		cmd->result = DID_OK << 16 |
18451da177e4SLinus Torvalds 			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
18468e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
18478e31e607SSalyzyn, Mark 		  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
18488e31e607SSalyzyn, Mark 		  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
18491da177e4SLinus Torvalds 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
1850b80ca4f7SFUJITA Tomonori 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
1851b80ca4f7SFUJITA Tomonori 			     SCSI_SENSE_BUFFERSIZE));
18521da177e4SLinus Torvalds 	}
18531da177e4SLinus Torvalds 
1854bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
1855bfb35aa8SMark Haverkamp 	aac_fib_free(fibptr);
18568e0c5ebdSMark Haverkamp 	cmd->scsi_done(cmd);
18571da177e4SLinus Torvalds }
18581da177e4SLinus Torvalds 
18599e7c349cSMark Haverkamp static int aac_synchronize(struct scsi_cmnd *scsicmd)
18601da177e4SLinus Torvalds {
18611da177e4SLinus Torvalds 	int status;
18621da177e4SLinus Torvalds 	struct fib *cmd_fibcontext;
18631da177e4SLinus Torvalds 	struct aac_synchronize *synchronizecmd;
18641da177e4SLinus Torvalds 	struct scsi_cmnd *cmd;
18651da177e4SLinus Torvalds 	struct scsi_device *sdev = scsicmd->device;
18661da177e4SLinus Torvalds 	int active = 0;
186790ee3466SMark Haverkamp 	struct aac_dev *aac;
1868b90f90d2SSalyzyn, Mark 	u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) |
1869b90f90d2SSalyzyn, Mark 		(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
1870b90f90d2SSalyzyn, Mark 	u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
18711da177e4SLinus Torvalds 	unsigned long flags;
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds 	/*
187477d644d4SMark Haverkamp 	 * Wait for all outstanding queued commands to complete to this
187577d644d4SMark Haverkamp 	 * specific target (block).
18761da177e4SLinus Torvalds 	 */
18771da177e4SLinus Torvalds 	spin_lock_irqsave(&sdev->list_lock, flags);
18781da177e4SLinus Torvalds 	list_for_each_entry(cmd, &sdev->cmd_list, list)
1879b90f90d2SSalyzyn, Mark 		if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
1880b90f90d2SSalyzyn, Mark 			u64 cmnd_lba;
1881b90f90d2SSalyzyn, Mark 			u32 cmnd_count;
1882b90f90d2SSalyzyn, Mark 
1883b90f90d2SSalyzyn, Mark 			if (cmd->cmnd[0] == WRITE_6) {
1884b90f90d2SSalyzyn, Mark 				cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) |
1885b90f90d2SSalyzyn, Mark 					(cmd->cmnd[2] << 8) |
1886b90f90d2SSalyzyn, Mark 					cmd->cmnd[3];
1887b90f90d2SSalyzyn, Mark 				cmnd_count = cmd->cmnd[4];
1888b90f90d2SSalyzyn, Mark 				if (cmnd_count == 0)
1889b90f90d2SSalyzyn, Mark 					cmnd_count = 256;
1890b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_16) {
1891b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 56) |
1892b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[3] << 48) |
1893b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[4] << 40) |
1894b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[5] << 32) |
1895b90f90d2SSalyzyn, Mark 					((u64)cmd->cmnd[6] << 24) |
1896b90f90d2SSalyzyn, Mark 					(cmd->cmnd[7] << 16) |
1897b90f90d2SSalyzyn, Mark 					(cmd->cmnd[8] << 8) |
1898b90f90d2SSalyzyn, Mark 					cmd->cmnd[9];
1899b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[10] << 24) |
1900b90f90d2SSalyzyn, Mark 					(cmd->cmnd[11] << 16) |
1901b90f90d2SSalyzyn, Mark 					(cmd->cmnd[12] << 8) |
1902b90f90d2SSalyzyn, Mark 					cmd->cmnd[13];
1903b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_12) {
1904b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
1905b90f90d2SSalyzyn, Mark 					(cmd->cmnd[3] << 16) |
1906b90f90d2SSalyzyn, Mark 					(cmd->cmnd[4] << 8) |
1907b90f90d2SSalyzyn, Mark 					cmd->cmnd[5];
1908b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[6] << 24) |
1909b90f90d2SSalyzyn, Mark 					(cmd->cmnd[7] << 16) |
1910b90f90d2SSalyzyn, Mark 					(cmd->cmnd[8] << 8) |
1911b90f90d2SSalyzyn, Mark 					cmd->cmnd[9];
1912b90f90d2SSalyzyn, Mark 			} else if (cmd->cmnd[0] == WRITE_10) {
1913b90f90d2SSalyzyn, Mark 				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
1914b90f90d2SSalyzyn, Mark 					(cmd->cmnd[3] << 16) |
1915b90f90d2SSalyzyn, Mark 					(cmd->cmnd[4] << 8) |
1916b90f90d2SSalyzyn, Mark 					cmd->cmnd[5];
1917b90f90d2SSalyzyn, Mark 				cmnd_count = (cmd->cmnd[7] << 8) |
1918b90f90d2SSalyzyn, Mark 					cmd->cmnd[8];
1919b90f90d2SSalyzyn, Mark 			} else
1920b90f90d2SSalyzyn, Mark 				continue;
1921b90f90d2SSalyzyn, Mark 			if (((cmnd_lba + cmnd_count) < lba) ||
1922b90f90d2SSalyzyn, Mark 			  (count && ((lba + count) < cmnd_lba)))
1923b90f90d2SSalyzyn, Mark 				continue;
19241da177e4SLinus Torvalds 			++active;
19251da177e4SLinus Torvalds 			break;
19261da177e4SLinus Torvalds 		}
19271da177e4SLinus Torvalds 
19281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&sdev->list_lock, flags);
19291da177e4SLinus Torvalds 
19301da177e4SLinus Torvalds 	/*
19311da177e4SLinus Torvalds 	 *	Yield the processor (requeue for later)
19321da177e4SLinus Torvalds 	 */
19331da177e4SLinus Torvalds 	if (active)
19341da177e4SLinus Torvalds 		return SCSI_MLQUEUE_DEVICE_BUSY;
19351da177e4SLinus Torvalds 
1936f858317dSSalyzyn, Mark 	aac = (struct aac_dev *)sdev->host->hostdata;
19378c867b25SMark Haverkamp 	if (aac->in_reset)
19388c867b25SMark Haverkamp 		return SCSI_MLQUEUE_HOST_BUSY;
19398c867b25SMark Haverkamp 
19401da177e4SLinus Torvalds 	/*
19417c00ffa3SMark Haverkamp  	 *	Allocate and initialize a Fib
19421da177e4SLinus Torvalds 	 */
194390ee3466SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(aac)))
19441da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
19451da177e4SLinus Torvalds 
1946bfb35aa8SMark Haverkamp 	aac_fib_init(cmd_fibcontext);
19471da177e4SLinus Torvalds 
19481da177e4SLinus Torvalds 	synchronizecmd = fib_data(cmd_fibcontext);
19491da177e4SLinus Torvalds 	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
19501da177e4SLinus Torvalds 	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
19519e7c349cSMark Haverkamp 	synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
19521da177e4SLinus Torvalds 	synchronizecmd->count =
19531da177e4SLinus Torvalds 	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds 	/*
19561da177e4SLinus Torvalds 	 *	Now send the Fib to the adapter
19571da177e4SLinus Torvalds 	 */
1958bfb35aa8SMark Haverkamp 	status = aac_fib_send(ContainerCommand,
19591da177e4SLinus Torvalds 		  cmd_fibcontext,
19601da177e4SLinus Torvalds 		  sizeof(struct aac_synchronize),
19611da177e4SLinus Torvalds 		  FsaNormal,
19621da177e4SLinus Torvalds 		  0, 1,
19631da177e4SLinus Torvalds 		  (fib_callback)synchronize_callback,
19641da177e4SLinus Torvalds 		  (void *)scsicmd);
19651da177e4SLinus Torvalds 
19661da177e4SLinus Torvalds 	/*
19671da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
19681da177e4SLinus Torvalds 	 */
196977d644d4SMark Haverkamp 	if (status == -EINPROGRESS) {
197077d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
19711da177e4SLinus Torvalds 		return 0;
197277d644d4SMark Haverkamp 	}
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds 	printk(KERN_WARNING
1975bfb35aa8SMark Haverkamp 		"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
1976bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
1977bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
19781da177e4SLinus Torvalds 	return SCSI_MLQUEUE_HOST_BUSY;
19791da177e4SLinus Torvalds }
19801da177e4SLinus Torvalds 
1981655d722cSMark Salyzyn static void aac_start_stop_callback(void *context, struct fib *fibptr)
1982655d722cSMark Salyzyn {
1983655d722cSMark Salyzyn 	struct scsi_cmnd *scsicmd = context;
1984655d722cSMark Salyzyn 
1985655d722cSMark Salyzyn 	if (!aac_valid_context(scsicmd, fibptr))
1986655d722cSMark Salyzyn 		return;
1987655d722cSMark Salyzyn 
1988655d722cSMark Salyzyn 	BUG_ON(fibptr == NULL);
1989655d722cSMark Salyzyn 
1990655d722cSMark Salyzyn 	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
1991655d722cSMark Salyzyn 
1992655d722cSMark Salyzyn 	aac_fib_complete(fibptr);
1993655d722cSMark Salyzyn 	aac_fib_free(fibptr);
1994655d722cSMark Salyzyn 	scsicmd->scsi_done(scsicmd);
1995655d722cSMark Salyzyn }
1996655d722cSMark Salyzyn 
1997655d722cSMark Salyzyn static int aac_start_stop(struct scsi_cmnd *scsicmd)
1998655d722cSMark Salyzyn {
1999655d722cSMark Salyzyn 	int status;
2000655d722cSMark Salyzyn 	struct fib *cmd_fibcontext;
2001655d722cSMark Salyzyn 	struct aac_power_management *pmcmd;
2002655d722cSMark Salyzyn 	struct scsi_device *sdev = scsicmd->device;
2003655d722cSMark Salyzyn 	struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
2004655d722cSMark Salyzyn 
2005655d722cSMark Salyzyn 	if (!(aac->supplement_adapter_info.SupportedOptions2 &
2006655d722cSMark Salyzyn 	      AAC_OPTION_POWER_MANAGEMENT)) {
2007655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2008655d722cSMark Salyzyn 				  SAM_STAT_GOOD;
2009655d722cSMark Salyzyn 		scsicmd->scsi_done(scsicmd);
2010655d722cSMark Salyzyn 		return 0;
2011655d722cSMark Salyzyn 	}
2012655d722cSMark Salyzyn 
2013655d722cSMark Salyzyn 	if (aac->in_reset)
2014655d722cSMark Salyzyn 		return SCSI_MLQUEUE_HOST_BUSY;
2015655d722cSMark Salyzyn 
2016655d722cSMark Salyzyn 	/*
2017655d722cSMark Salyzyn 	 *	Allocate and initialize a Fib
2018655d722cSMark Salyzyn 	 */
2019655d722cSMark Salyzyn 	cmd_fibcontext = aac_fib_alloc(aac);
2020655d722cSMark Salyzyn 	if (!cmd_fibcontext)
2021655d722cSMark Salyzyn 		return SCSI_MLQUEUE_HOST_BUSY;
2022655d722cSMark Salyzyn 
2023655d722cSMark Salyzyn 	aac_fib_init(cmd_fibcontext);
2024655d722cSMark Salyzyn 
2025655d722cSMark Salyzyn 	pmcmd = fib_data(cmd_fibcontext);
2026655d722cSMark Salyzyn 	pmcmd->command = cpu_to_le32(VM_ContainerConfig);
2027655d722cSMark Salyzyn 	pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
2028655d722cSMark Salyzyn 	/* Eject bit ignored, not relevant */
2029655d722cSMark Salyzyn 	pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
2030655d722cSMark Salyzyn 		cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
2031655d722cSMark Salyzyn 	pmcmd->cid = cpu_to_le32(sdev_id(sdev));
2032655d722cSMark Salyzyn 	pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
2033655d722cSMark Salyzyn 		cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
2034655d722cSMark Salyzyn 
2035655d722cSMark Salyzyn 	/*
2036655d722cSMark Salyzyn 	 *	Now send the Fib to the adapter
2037655d722cSMark Salyzyn 	 */
2038655d722cSMark Salyzyn 	status = aac_fib_send(ContainerCommand,
2039655d722cSMark Salyzyn 		  cmd_fibcontext,
2040655d722cSMark Salyzyn 		  sizeof(struct aac_power_management),
2041655d722cSMark Salyzyn 		  FsaNormal,
2042655d722cSMark Salyzyn 		  0, 1,
2043655d722cSMark Salyzyn 		  (fib_callback)aac_start_stop_callback,
2044655d722cSMark Salyzyn 		  (void *)scsicmd);
2045655d722cSMark Salyzyn 
2046655d722cSMark Salyzyn 	/*
2047655d722cSMark Salyzyn 	 *	Check that the command queued to the controller
2048655d722cSMark Salyzyn 	 */
2049655d722cSMark Salyzyn 	if (status == -EINPROGRESS) {
2050655d722cSMark Salyzyn 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2051655d722cSMark Salyzyn 		return 0;
2052655d722cSMark Salyzyn 	}
2053655d722cSMark Salyzyn 
2054655d722cSMark Salyzyn 	aac_fib_complete(cmd_fibcontext);
2055655d722cSMark Salyzyn 	aac_fib_free(cmd_fibcontext);
2056655d722cSMark Salyzyn 	return SCSI_MLQUEUE_HOST_BUSY;
2057655d722cSMark Salyzyn }
2058655d722cSMark Salyzyn 
20591da177e4SLinus Torvalds /**
20601da177e4SLinus Torvalds  *	aac_scsi_cmd()		-	Process SCSI command
20611da177e4SLinus Torvalds  *	@scsicmd:		SCSI command block
20621da177e4SLinus Torvalds  *
20631da177e4SLinus Torvalds  *	Emulate a SCSI command and queue the required request for the
20641da177e4SLinus Torvalds  *	aacraid firmware.
20651da177e4SLinus Torvalds  */
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
20681da177e4SLinus Torvalds {
20691a655040SSalyzyn, Mark 	u32 cid;
20701da177e4SLinus Torvalds 	struct Scsi_Host *host = scsicmd->device->host;
20711da177e4SLinus Torvalds 	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
20721da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
20731da177e4SLinus Torvalds 
207490ee3466SMark Haverkamp 	if (fsa_dev_ptr == NULL)
207590ee3466SMark Haverkamp 		return -1;
20761da177e4SLinus Torvalds 	/*
20771da177e4SLinus Torvalds 	 *	If the bus, id or lun is out of range, return fail
20781da177e4SLinus Torvalds 	 *	Test does not apply to ID 16, the pseudo id for the controller
20791da177e4SLinus Torvalds 	 *	itself.
20801da177e4SLinus Torvalds 	 */
20811a655040SSalyzyn, Mark 	cid = scmd_id(scsicmd);
20821a655040SSalyzyn, Mark 	if (cid != host->this_id) {
20831a655040SSalyzyn, Mark 		if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) {
20841a655040SSalyzyn, Mark 			if((cid >= dev->maximum_num_containers) ||
2085e5718774SMark Haverkamp 					(scsicmd->device->lun != 0)) {
20861da177e4SLinus Torvalds 				scsicmd->result = DID_NO_CONNECT << 16;
20871da177e4SLinus Torvalds 				scsicmd->scsi_done(scsicmd);
20881da177e4SLinus Torvalds 				return 0;
20891da177e4SLinus Torvalds 			}
20901da177e4SLinus Torvalds 
20911da177e4SLinus Torvalds 			/*
20921da177e4SLinus Torvalds 			 *	If the target container doesn't exist, it may have
20931da177e4SLinus Torvalds 			 *	been newly created
20941da177e4SLinus Torvalds 			 */
2095655d722cSMark Salyzyn 			if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
2096655d722cSMark Salyzyn 			  (fsa_dev_ptr[cid].sense_data.sense_key ==
2097655d722cSMark Salyzyn 			   NOT_READY)) {
20981da177e4SLinus Torvalds 				switch (scsicmd->cmnd[0]) {
20997a8cf29dSMark Haverkamp 				case SERVICE_ACTION_IN:
21007a8cf29dSMark Haverkamp 					if (!(dev->raw_io_interface) ||
21017a8cf29dSMark Haverkamp 					    !(dev->raw_io_64) ||
21027a8cf29dSMark Haverkamp 					    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
21037a8cf29dSMark Haverkamp 						break;
21041da177e4SLinus Torvalds 				case INQUIRY:
21051da177e4SLinus Torvalds 				case READ_CAPACITY:
21061da177e4SLinus Torvalds 				case TEST_UNIT_READY:
21078c867b25SMark Haverkamp 					if (dev->in_reset)
21088c867b25SMark Haverkamp 						return -1;
2109fe76df42SMark Haverkamp 					return _aac_probe_container(scsicmd,
2110fe76df42SMark Haverkamp 							aac_probe_container_callback2);
21111da177e4SLinus Torvalds 				default:
21121da177e4SLinus Torvalds 					break;
21131da177e4SLinus Torvalds 				}
21141da177e4SLinus Torvalds 			}
21151da177e4SLinus Torvalds 		} else {  /* check for physical non-dasd devices */
2116cb1042f2SSalyzyn, Mark 			if (dev->nondasd_support || expose_physicals ||
2117cb1042f2SSalyzyn, Mark 					dev->jbod) {
21188c867b25SMark Haverkamp 				if (dev->in_reset)
21198c867b25SMark Haverkamp 					return -1;
21201da177e4SLinus Torvalds 				return aac_send_srb_fib(scsicmd);
21211da177e4SLinus Torvalds 			} else {
21221da177e4SLinus Torvalds 				scsicmd->result = DID_NO_CONNECT << 16;
21231da177e4SLinus Torvalds 				scsicmd->scsi_done(scsicmd);
21241da177e4SLinus Torvalds 				return 0;
21251da177e4SLinus Torvalds 			}
21261da177e4SLinus Torvalds 		}
21271da177e4SLinus Torvalds 	}
21281da177e4SLinus Torvalds 	/*
21291da177e4SLinus Torvalds 	 * else Command for the controller itself
21301da177e4SLinus Torvalds 	 */
21311da177e4SLinus Torvalds 	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
21321da177e4SLinus Torvalds 		(scsicmd->cmnd[0] != TEST_UNIT_READY))
21331da177e4SLinus Torvalds 	{
21341da177e4SLinus Torvalds 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
21351da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
21368e31e607SSalyzyn, Mark 		set_sense(&dev->fsa_dev[cid].sense_data,
21378e31e607SSalyzyn, Mark 		  ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
21388e31e607SSalyzyn, Mark 		  ASENCODE_INVALID_COMMAND, 0, 0);
21391da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
21403ace426fSSalyzyn, Mark 		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
21413ace426fSSalyzyn, Mark 			     SCSI_SENSE_BUFFERSIZE));
21421da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
21431da177e4SLinus Torvalds 		return 0;
21441da177e4SLinus Torvalds 	}
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 
21471da177e4SLinus Torvalds 	/* Handle commands here that don't really require going out to the adapter */
21481da177e4SLinus Torvalds 	switch (scsicmd->cmnd[0]) {
21491da177e4SLinus Torvalds 	case INQUIRY:
21501da177e4SLinus Torvalds 	{
21513b2946ccSMark Haverkamp 		struct inquiry_data inq_data;
21521da177e4SLinus Torvalds 
21531a655040SSalyzyn, Mark 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
21543b2946ccSMark Haverkamp 		memset(&inq_data, 0, sizeof (struct inquiry_data));
21551da177e4SLinus Torvalds 
2156d8e96507SLeubner, Achim 		if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) {
215788e2f98eSSalyzyn, Mark 			char *arr = (char *)&inq_data;
215888e2f98eSSalyzyn, Mark 
215988e2f98eSSalyzyn, Mark 			/* EVPD bit set */
216088e2f98eSSalyzyn, Mark 			arr[0] = (scmd_id(scsicmd) == host->this_id) ?
216188e2f98eSSalyzyn, Mark 			  INQD_PDT_PROC : INQD_PDT_DA;
216288e2f98eSSalyzyn, Mark 			if (scsicmd->cmnd[2] == 0) {
216388e2f98eSSalyzyn, Mark 				/* supported vital product data pages */
216488e2f98eSSalyzyn, Mark 				arr[3] = 2;
216588e2f98eSSalyzyn, Mark 				arr[4] = 0x0;
216688e2f98eSSalyzyn, Mark 				arr[5] = 0x80;
216788e2f98eSSalyzyn, Mark 				arr[1] = scsicmd->cmnd[2];
2168d4345028SFUJITA Tomonori 				scsi_sg_copy_from_buffer(scsicmd, &inq_data,
216988e2f98eSSalyzyn, Mark 							 sizeof(inq_data));
217088e2f98eSSalyzyn, Mark 				scsicmd->result = DID_OK << 16 |
217188e2f98eSSalyzyn, Mark 				  COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
217288e2f98eSSalyzyn, Mark 			} else if (scsicmd->cmnd[2] == 0x80) {
217388e2f98eSSalyzyn, Mark 				/* unit serial number page */
217488e2f98eSSalyzyn, Mark 				arr[3] = setinqserial(dev, &arr[4],
217588e2f98eSSalyzyn, Mark 				  scmd_id(scsicmd));
217688e2f98eSSalyzyn, Mark 				arr[1] = scsicmd->cmnd[2];
2177d4345028SFUJITA Tomonori 				scsi_sg_copy_from_buffer(scsicmd, &inq_data,
217888e2f98eSSalyzyn, Mark 							 sizeof(inq_data));
2179d8e96507SLeubner, Achim 				if (aac_wwn != 2)
2180d8e96507SLeubner, Achim 					return aac_get_container_serial(
2181d8e96507SLeubner, Achim 						scsicmd);
2182d8e96507SLeubner, Achim 				/* SLES 10 SP1 special */
2183d8e96507SLeubner, Achim 				scsicmd->result = DID_OK << 16 |
2184d8e96507SLeubner, Achim 				  COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
218588e2f98eSSalyzyn, Mark 			} else {
218688e2f98eSSalyzyn, Mark 				/* vpd page not implemented */
218788e2f98eSSalyzyn, Mark 				scsicmd->result = DID_OK << 16 |
218888e2f98eSSalyzyn, Mark 				  COMMAND_COMPLETE << 8 |
218988e2f98eSSalyzyn, Mark 				  SAM_STAT_CHECK_CONDITION;
21908e31e607SSalyzyn, Mark 				set_sense(&dev->fsa_dev[cid].sense_data,
21918e31e607SSalyzyn, Mark 				  ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD,
21928e31e607SSalyzyn, Mark 				  ASENCODE_NO_SENSE, 7, 2);
219388e2f98eSSalyzyn, Mark 				memcpy(scsicmd->sense_buffer,
219488e2f98eSSalyzyn, Mark 				  &dev->fsa_dev[cid].sense_data,
21953ace426fSSalyzyn, Mark 				  min_t(size_t,
21963ace426fSSalyzyn, Mark 					sizeof(dev->fsa_dev[cid].sense_data),
21973ace426fSSalyzyn, Mark 					SCSI_SENSE_BUFFERSIZE));
219888e2f98eSSalyzyn, Mark 			}
219988e2f98eSSalyzyn, Mark 			scsicmd->scsi_done(scsicmd);
220088e2f98eSSalyzyn, Mark 			return 0;
220188e2f98eSSalyzyn, Mark 		}
22023b2946ccSMark Haverkamp 		inq_data.inqd_ver = 2;	/* claim compliance to SCSI-2 */
22033b2946ccSMark 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 */
22043b2946ccSMark Haverkamp 		inq_data.inqd_len = 31;
22051da177e4SLinus Torvalds 		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
22063b2946ccSMark Haverkamp 		inq_data.inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
22071da177e4SLinus Torvalds 		/*
22081da177e4SLinus Torvalds 		 *	Set the Vendor, Product, and Revision Level
22091da177e4SLinus Torvalds 		 *	see: <vendor>.c i.e. aac.c
22101da177e4SLinus Torvalds 		 */
22111a655040SSalyzyn, Mark 		if (cid == host->this_id) {
22126391a113STobias Klauser 			setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
22133b2946ccSMark Haverkamp 			inq_data.inqd_pdt = INQD_PDT_PROC;	/* Processor device */
2214d4345028SFUJITA Tomonori 			scsi_sg_copy_from_buffer(scsicmd, &inq_data,
2215d4345028SFUJITA Tomonori 						 sizeof(inq_data));
22161da177e4SLinus Torvalds 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
22171da177e4SLinus Torvalds 			scsicmd->scsi_done(scsicmd);
22181da177e4SLinus Torvalds 			return 0;
22191da177e4SLinus Torvalds 		}
22208c867b25SMark Haverkamp 		if (dev->in_reset)
22218c867b25SMark Haverkamp 			return -1;
2222794d0601SMark Haverkamp 		setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
22233b2946ccSMark Haverkamp 		inq_data.inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
2224d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
22259e7c349cSMark Haverkamp 		return aac_get_container_name(scsicmd);
22261da177e4SLinus Torvalds 	}
22277a8cf29dSMark Haverkamp 	case SERVICE_ACTION_IN:
22287a8cf29dSMark Haverkamp 		if (!(dev->raw_io_interface) ||
22297a8cf29dSMark Haverkamp 		    !(dev->raw_io_64) ||
22307a8cf29dSMark Haverkamp 		    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
22317a8cf29dSMark Haverkamp 			break;
22327a8cf29dSMark Haverkamp 	{
22337a8cf29dSMark Haverkamp 		u64 capacity;
223407ce5ebaSMark Haverkamp 		char cp[13];
2235b271f1c8SFUJITA Tomonori 		unsigned int alloc_len;
22367a8cf29dSMark Haverkamp 
22377a8cf29dSMark Haverkamp 		dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
22387a8cf29dSMark Haverkamp 		capacity = fsa_dev_ptr[cid].size - 1;
22397a8cf29dSMark Haverkamp 		cp[0] = (capacity >> 56) & 0xff;
22407a8cf29dSMark Haverkamp 		cp[1] = (capacity >> 48) & 0xff;
22417a8cf29dSMark Haverkamp 		cp[2] = (capacity >> 40) & 0xff;
22427a8cf29dSMark Haverkamp 		cp[3] = (capacity >> 32) & 0xff;
22437a8cf29dSMark Haverkamp 		cp[4] = (capacity >> 24) & 0xff;
22447a8cf29dSMark Haverkamp 		cp[5] = (capacity >> 16) & 0xff;
22457a8cf29dSMark Haverkamp 		cp[6] = (capacity >> 8) & 0xff;
22467a8cf29dSMark Haverkamp 		cp[7] = (capacity >> 0) & 0xff;
22477a8cf29dSMark Haverkamp 		cp[8] = 0;
22487a8cf29dSMark Haverkamp 		cp[9] = 0;
22497a8cf29dSMark Haverkamp 		cp[10] = 2;
22507a8cf29dSMark Haverkamp 		cp[11] = 0;
225107ce5ebaSMark Haverkamp 		cp[12] = 0;
225207ce5ebaSMark Haverkamp 
2253b271f1c8SFUJITA Tomonori 		alloc_len = ((scsicmd->cmnd[10] << 24)
2254b271f1c8SFUJITA Tomonori 			     + (scsicmd->cmnd[11] << 16)
2255b271f1c8SFUJITA Tomonori 			     + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]);
2256b271f1c8SFUJITA Tomonori 
2257b271f1c8SFUJITA Tomonori 		alloc_len = min_t(size_t, alloc_len, sizeof(cp));
2258d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len);
2259b271f1c8SFUJITA Tomonori 		if (alloc_len < scsi_bufflen(scsicmd))
2260b271f1c8SFUJITA Tomonori 			scsi_set_resid(scsicmd,
2261b271f1c8SFUJITA Tomonori 				       scsi_bufflen(scsicmd) - alloc_len);
22627a8cf29dSMark Haverkamp 
22637a8cf29dSMark Haverkamp 		/* Do not cache partition table for arrays */
22647a8cf29dSMark Haverkamp 		scsicmd->device->removable = 1;
22657a8cf29dSMark Haverkamp 
22667a8cf29dSMark Haverkamp 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
22677a8cf29dSMark Haverkamp 		scsicmd->scsi_done(scsicmd);
22687a8cf29dSMark Haverkamp 
22697a8cf29dSMark Haverkamp 		return 0;
22707a8cf29dSMark Haverkamp 	}
22717a8cf29dSMark Haverkamp 
22721da177e4SLinus Torvalds 	case READ_CAPACITY:
22731da177e4SLinus Torvalds 	{
22741da177e4SLinus Torvalds 		u32 capacity;
22753b2946ccSMark Haverkamp 		char cp[8];
22761da177e4SLinus Torvalds 
22771da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
22787a8cf29dSMark Haverkamp 		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
22791da177e4SLinus Torvalds 			capacity = fsa_dev_ptr[cid].size - 1;
22801da177e4SLinus Torvalds 		else
22811da177e4SLinus Torvalds 			capacity = (u32)-1;
22823b2946ccSMark Haverkamp 
22831da177e4SLinus Torvalds 		cp[0] = (capacity >> 24) & 0xff;
22841da177e4SLinus Torvalds 		cp[1] = (capacity >> 16) & 0xff;
22851da177e4SLinus Torvalds 		cp[2] = (capacity >> 8) & 0xff;
22861da177e4SLinus Torvalds 		cp[3] = (capacity >> 0) & 0xff;
22871da177e4SLinus Torvalds 		cp[4] = 0;
22881da177e4SLinus Torvalds 		cp[5] = 0;
22891da177e4SLinus Torvalds 		cp[6] = 2;
22901da177e4SLinus Torvalds 		cp[7] = 0;
2291d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
22927a8cf29dSMark Haverkamp 		/* Do not cache partition table for arrays */
22937a8cf29dSMark Haverkamp 		scsicmd->device->removable = 1;
2294655d722cSMark Salyzyn 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2295655d722cSMark Salyzyn 		  SAM_STAT_GOOD;
22961da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
22971da177e4SLinus Torvalds 
22981da177e4SLinus Torvalds 		return 0;
22991da177e4SLinus Torvalds 	}
23001da177e4SLinus Torvalds 
23011da177e4SLinus Torvalds 	case MODE_SENSE:
23021da177e4SLinus Torvalds 	{
23039d399cc7SSalyzyn, Mark 		char mode_buf[7];
23049d399cc7SSalyzyn, Mark 		int mode_buf_length = 4;
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "MODE SENSE command.\n"));
23071da177e4SLinus Torvalds 		mode_buf[0] = 3;	/* Mode data length */
23081da177e4SLinus Torvalds 		mode_buf[1] = 0;	/* Medium type - default */
23099d399cc7SSalyzyn, Mark 		mode_buf[2] = 0;	/* Device-specific param,
23109d399cc7SSalyzyn, Mark 					   bit 8: 0/1 = write enabled/protected
23119d399cc7SSalyzyn, Mark 					   bit 4: 0/1 = FUA enabled */
231295e852e1SSalyzyn, Mark 		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
23139d399cc7SSalyzyn, Mark 			mode_buf[2] = 0x10;
23141da177e4SLinus Torvalds 		mode_buf[3] = 0;	/* Block descriptor length */
23159d399cc7SSalyzyn, Mark 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
23169d399cc7SSalyzyn, Mark 		  ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
23179d399cc7SSalyzyn, Mark 			mode_buf[0] = 6;
23189d399cc7SSalyzyn, Mark 			mode_buf[4] = 8;
23199d399cc7SSalyzyn, Mark 			mode_buf[5] = 1;
232095e852e1SSalyzyn, Mark 			mode_buf[6] = ((aac_cache & 6) == 2)
232195e852e1SSalyzyn, Mark 				? 0 : 0x04; /* WCE */
23229d399cc7SSalyzyn, Mark 			mode_buf_length = 7;
23239d399cc7SSalyzyn, Mark 			if (mode_buf_length > scsicmd->cmnd[4])
23249d399cc7SSalyzyn, Mark 				mode_buf_length = scsicmd->cmnd[4];
23259d399cc7SSalyzyn, Mark 		}
2326d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length);
23271da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
23281da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
23291da177e4SLinus Torvalds 
23301da177e4SLinus Torvalds 		return 0;
23311da177e4SLinus Torvalds 	}
23321da177e4SLinus Torvalds 	case MODE_SENSE_10:
23331da177e4SLinus Torvalds 	{
23349d399cc7SSalyzyn, Mark 		char mode_buf[11];
23359d399cc7SSalyzyn, Mark 		int mode_buf_length = 8;
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
23381da177e4SLinus Torvalds 		mode_buf[0] = 0;	/* Mode data length (MSB) */
23391da177e4SLinus Torvalds 		mode_buf[1] = 6;	/* Mode data length (LSB) */
23401da177e4SLinus Torvalds 		mode_buf[2] = 0;	/* Medium type - default */
23419d399cc7SSalyzyn, Mark 		mode_buf[3] = 0;	/* Device-specific param,
23429d399cc7SSalyzyn, Mark 					   bit 8: 0/1 = write enabled/protected
23439d399cc7SSalyzyn, Mark 					   bit 4: 0/1 = FUA enabled */
234495e852e1SSalyzyn, Mark 		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
23459d399cc7SSalyzyn, Mark 			mode_buf[3] = 0x10;
23461da177e4SLinus Torvalds 		mode_buf[4] = 0;	/* reserved */
23471da177e4SLinus Torvalds 		mode_buf[5] = 0;	/* reserved */
23481da177e4SLinus Torvalds 		mode_buf[6] = 0;	/* Block descriptor length (MSB) */
23491da177e4SLinus Torvalds 		mode_buf[7] = 0;	/* Block descriptor length (LSB) */
23509d399cc7SSalyzyn, Mark 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
23519d399cc7SSalyzyn, Mark 		  ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
23529d399cc7SSalyzyn, Mark 			mode_buf[1] = 9;
23539d399cc7SSalyzyn, Mark 			mode_buf[8] = 8;
23549d399cc7SSalyzyn, Mark 			mode_buf[9] = 1;
235595e852e1SSalyzyn, Mark 			mode_buf[10] = ((aac_cache & 6) == 2)
235695e852e1SSalyzyn, Mark 				? 0 : 0x04; /* WCE */
23579d399cc7SSalyzyn, Mark 			mode_buf_length = 11;
23589d399cc7SSalyzyn, Mark 			if (mode_buf_length > scsicmd->cmnd[8])
23599d399cc7SSalyzyn, Mark 				mode_buf_length = scsicmd->cmnd[8];
23609d399cc7SSalyzyn, Mark 		}
2361d4345028SFUJITA Tomonori 		scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length);
23621da177e4SLinus Torvalds 
23631da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
23641da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 		return 0;
23671da177e4SLinus Torvalds 	}
23681da177e4SLinus Torvalds 	case REQUEST_SENSE:
23691da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
23701da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data));
23711da177e4SLinus Torvalds 		memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data));
23721da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
23731da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
23741da177e4SLinus Torvalds 		return 0;
23751da177e4SLinus Torvalds 
23761da177e4SLinus Torvalds 	case ALLOW_MEDIUM_REMOVAL:
23771da177e4SLinus Torvalds 		dprintk((KERN_DEBUG "LOCK command.\n"));
23781da177e4SLinus Torvalds 		if (scsicmd->cmnd[4])
23791da177e4SLinus Torvalds 			fsa_dev_ptr[cid].locked = 1;
23801da177e4SLinus Torvalds 		else
23811da177e4SLinus Torvalds 			fsa_dev_ptr[cid].locked = 0;
23821da177e4SLinus Torvalds 
23831da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
23841da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
23851da177e4SLinus Torvalds 		return 0;
23861da177e4SLinus Torvalds 	/*
23871da177e4SLinus Torvalds 	 *	These commands are all No-Ops
23881da177e4SLinus Torvalds 	 */
23891da177e4SLinus Torvalds 	case TEST_UNIT_READY:
2390655d722cSMark Salyzyn 		if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
2391655d722cSMark Salyzyn 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
2392655d722cSMark Salyzyn 				SAM_STAT_CHECK_CONDITION;
2393655d722cSMark Salyzyn 			set_sense(&dev->fsa_dev[cid].sense_data,
2394655d722cSMark Salyzyn 				  NOT_READY, SENCODE_BECOMING_READY,
2395655d722cSMark Salyzyn 				  ASENCODE_BECOMING_READY, 0, 0);
2396655d722cSMark Salyzyn 			memcpy(scsicmd->sense_buffer,
2397655d722cSMark Salyzyn 			       &dev->fsa_dev[cid].sense_data,
2398655d722cSMark Salyzyn 			       min_t(size_t,
2399655d722cSMark Salyzyn 				     sizeof(dev->fsa_dev[cid].sense_data),
2400655d722cSMark Salyzyn 				     SCSI_SENSE_BUFFERSIZE));
2401655d722cSMark Salyzyn 			scsicmd->scsi_done(scsicmd);
2402655d722cSMark Salyzyn 			return 0;
2403655d722cSMark Salyzyn 		}
2404655d722cSMark Salyzyn 		/* FALLTHRU */
24051da177e4SLinus Torvalds 	case RESERVE:
24061da177e4SLinus Torvalds 	case RELEASE:
24071da177e4SLinus Torvalds 	case REZERO_UNIT:
24081da177e4SLinus Torvalds 	case REASSIGN_BLOCKS:
24091da177e4SLinus Torvalds 	case SEEK_10:
24101da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
24111da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
24121da177e4SLinus Torvalds 		return 0;
2413655d722cSMark Salyzyn 
2414655d722cSMark Salyzyn 	case START_STOP:
2415655d722cSMark Salyzyn 		return aac_start_stop(scsicmd);
24161da177e4SLinus Torvalds 	}
24171da177e4SLinus Torvalds 
24181da177e4SLinus Torvalds 	switch (scsicmd->cmnd[0])
24191da177e4SLinus Torvalds 	{
24201da177e4SLinus Torvalds 		case READ_6:
24211da177e4SLinus Torvalds 		case READ_10:
24227a8cf29dSMark Haverkamp 		case READ_12:
24237a8cf29dSMark Haverkamp 		case READ_16:
24248c867b25SMark Haverkamp 			if (dev->in_reset)
24258c867b25SMark Haverkamp 				return -1;
24261da177e4SLinus Torvalds 			/*
24271da177e4SLinus Torvalds 			 *	Hack to keep track of ordinal number of the device that
24281da177e4SLinus Torvalds 			 *	corresponds to a container. Needed to convert
24291da177e4SLinus Torvalds 			 *	containers to /dev/sd device names
24301da177e4SLinus Torvalds 			 */
24311da177e4SLinus Torvalds 
24321da177e4SLinus Torvalds 			if (scsicmd->request->rq_disk)
24337a8cf29dSMark Haverkamp 				strlcpy(fsa_dev_ptr[cid].devname,
24341da177e4SLinus Torvalds 				scsicmd->request->rq_disk->disk_name,
24357a8cf29dSMark Haverkamp 				min(sizeof(fsa_dev_ptr[cid].devname),
24367a8cf29dSMark Haverkamp 				sizeof(scsicmd->request->rq_disk->disk_name) + 1));
243777d644d4SMark Haverkamp 
24389e7c349cSMark Haverkamp 			return aac_read(scsicmd);
24391da177e4SLinus Torvalds 
24401da177e4SLinus Torvalds 		case WRITE_6:
24411da177e4SLinus Torvalds 		case WRITE_10:
24427a8cf29dSMark Haverkamp 		case WRITE_12:
24437a8cf29dSMark Haverkamp 		case WRITE_16:
24448c867b25SMark Haverkamp 			if (dev->in_reset)
24458c867b25SMark Haverkamp 				return -1;
24469e7c349cSMark Haverkamp 			return aac_write(scsicmd);
24471da177e4SLinus Torvalds 
24481da177e4SLinus Torvalds 		case SYNCHRONIZE_CACHE:
244995e852e1SSalyzyn, Mark 			if (((aac_cache & 6) == 6) && dev->cache_protected) {
245095e852e1SSalyzyn, Mark 				scsicmd->result = DID_OK << 16 |
245195e852e1SSalyzyn, Mark 					COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
245295e852e1SSalyzyn, Mark 				scsicmd->scsi_done(scsicmd);
245395e852e1SSalyzyn, Mark 				return 0;
245495e852e1SSalyzyn, Mark 			}
24551da177e4SLinus Torvalds 			/* Issue FIB to tell Firmware to flush it's cache */
245695e852e1SSalyzyn, Mark 			if ((aac_cache & 6) != 2)
24579e7c349cSMark Haverkamp 				return aac_synchronize(scsicmd);
245895e852e1SSalyzyn, Mark 			/* FALLTHRU */
24591da177e4SLinus Torvalds 		default:
24601da177e4SLinus Torvalds 			/*
24611da177e4SLinus Torvalds 			 *	Unhandled commands
24621da177e4SLinus Torvalds 			 */
24637c00ffa3SMark Haverkamp  			dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]));
24641da177e4SLinus Torvalds 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
24658e31e607SSalyzyn, Mark 			set_sense(&dev->fsa_dev[cid].sense_data,
24661da177e4SLinus Torvalds 			  ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
24678e31e607SSalyzyn, Mark 			  ASENCODE_INVALID_COMMAND, 0, 0);
24681da177e4SLinus Torvalds 			memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
24693ace426fSSalyzyn, Mark 				min_t(size_t,
24703ace426fSSalyzyn, Mark 				      sizeof(dev->fsa_dev[cid].sense_data),
24713ace426fSSalyzyn, Mark 				      SCSI_SENSE_BUFFERSIZE));
24721da177e4SLinus Torvalds 			scsicmd->scsi_done(scsicmd);
24731da177e4SLinus Torvalds 			return 0;
24741da177e4SLinus Torvalds 	}
24751da177e4SLinus Torvalds }
24761da177e4SLinus Torvalds 
24771da177e4SLinus Torvalds static int query_disk(struct aac_dev *dev, void __user *arg)
24781da177e4SLinus Torvalds {
24791da177e4SLinus Torvalds 	struct aac_query_disk qd;
24801da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
24811da177e4SLinus Torvalds 
24821da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
248390ee3466SMark Haverkamp 	if (!fsa_dev_ptr)
248465101355SMark Haverkamp 		return -EBUSY;
24851da177e4SLinus Torvalds 	if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
24861da177e4SLinus Torvalds 		return -EFAULT;
24871da177e4SLinus Torvalds 	if (qd.cnum == -1)
2488e5718774SMark Haverkamp 		qd.cnum = qd.id;
24891da177e4SLinus Torvalds 	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
24901da177e4SLinus Torvalds 	{
24911da177e4SLinus Torvalds 		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
24921da177e4SLinus Torvalds 			return -EINVAL;
24931da177e4SLinus Torvalds 		qd.instance = dev->scsi_host_ptr->host_no;
24941da177e4SLinus Torvalds 		qd.bus = 0;
24951da177e4SLinus Torvalds 		qd.id = CONTAINER_TO_ID(qd.cnum);
24961da177e4SLinus Torvalds 		qd.lun = CONTAINER_TO_LUN(qd.cnum);
24971da177e4SLinus Torvalds 	}
24981da177e4SLinus Torvalds 	else return -EINVAL;
24991da177e4SLinus Torvalds 
2500fd622b1bSSalyzyn, Mark 	qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
25011da177e4SLinus Torvalds 	qd.locked = fsa_dev_ptr[qd.cnum].locked;
25021da177e4SLinus Torvalds 	qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
25031da177e4SLinus Torvalds 
25041da177e4SLinus Torvalds 	if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
25051da177e4SLinus Torvalds 		qd.unmapped = 1;
25061da177e4SLinus Torvalds 	else
25071da177e4SLinus Torvalds 		qd.unmapped = 0;
25081da177e4SLinus Torvalds 
25091da177e4SLinus Torvalds 	strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
25101da177e4SLinus Torvalds 	  min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds 	if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
25131da177e4SLinus Torvalds 		return -EFAULT;
25141da177e4SLinus Torvalds 	return 0;
25151da177e4SLinus Torvalds }
25161da177e4SLinus Torvalds 
25171da177e4SLinus Torvalds static int force_delete_disk(struct aac_dev *dev, void __user *arg)
25181da177e4SLinus Torvalds {
25191da177e4SLinus Torvalds 	struct aac_delete_disk dd;
25201da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
25211da177e4SLinus Torvalds 
25221da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
252365101355SMark Haverkamp 	if (!fsa_dev_ptr)
252465101355SMark Haverkamp 		return -EBUSY;
25251da177e4SLinus Torvalds 
25261da177e4SLinus Torvalds 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
25271da177e4SLinus Torvalds 		return -EFAULT;
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds 	if (dd.cnum >= dev->maximum_num_containers)
25301da177e4SLinus Torvalds 		return -EINVAL;
25311da177e4SLinus Torvalds 	/*
25321da177e4SLinus Torvalds 	 *	Mark this container as being deleted.
25331da177e4SLinus Torvalds 	 */
25341da177e4SLinus Torvalds 	fsa_dev_ptr[dd.cnum].deleted = 1;
25351da177e4SLinus Torvalds 	/*
25361da177e4SLinus Torvalds 	 *	Mark the container as no longer valid
25371da177e4SLinus Torvalds 	 */
25381da177e4SLinus Torvalds 	fsa_dev_ptr[dd.cnum].valid = 0;
25391da177e4SLinus Torvalds 	return 0;
25401da177e4SLinus Torvalds }
25411da177e4SLinus Torvalds 
25421da177e4SLinus Torvalds static int delete_disk(struct aac_dev *dev, void __user *arg)
25431da177e4SLinus Torvalds {
25441da177e4SLinus Torvalds 	struct aac_delete_disk dd;
25451da177e4SLinus Torvalds 	struct fsa_dev_info *fsa_dev_ptr;
25461da177e4SLinus Torvalds 
25471da177e4SLinus Torvalds 	fsa_dev_ptr = dev->fsa_dev;
254890ee3466SMark Haverkamp 	if (!fsa_dev_ptr)
254965101355SMark Haverkamp 		return -EBUSY;
25501da177e4SLinus Torvalds 
25511da177e4SLinus Torvalds 	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
25521da177e4SLinus Torvalds 		return -EFAULT;
25531da177e4SLinus Torvalds 
25541da177e4SLinus Torvalds 	if (dd.cnum >= dev->maximum_num_containers)
25551da177e4SLinus Torvalds 		return -EINVAL;
25561da177e4SLinus Torvalds 	/*
25571da177e4SLinus Torvalds 	 *	If the container is locked, it can not be deleted by the API.
25581da177e4SLinus Torvalds 	 */
25591da177e4SLinus Torvalds 	if (fsa_dev_ptr[dd.cnum].locked)
25601da177e4SLinus Torvalds 		return -EBUSY;
25611da177e4SLinus Torvalds 	else {
25621da177e4SLinus Torvalds 		/*
25631da177e4SLinus Torvalds 		 *	Mark the container as no longer being valid.
25641da177e4SLinus Torvalds 		 */
25651da177e4SLinus Torvalds 		fsa_dev_ptr[dd.cnum].valid = 0;
25661da177e4SLinus Torvalds 		fsa_dev_ptr[dd.cnum].devname[0] = '\0';
25671da177e4SLinus Torvalds 		return 0;
25681da177e4SLinus Torvalds 	}
25691da177e4SLinus Torvalds }
25701da177e4SLinus Torvalds 
25711da177e4SLinus Torvalds int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
25721da177e4SLinus Torvalds {
25731da177e4SLinus Torvalds 	switch (cmd) {
25741da177e4SLinus Torvalds 	case FSACTL_QUERY_DISK:
25751da177e4SLinus Torvalds 		return query_disk(dev, arg);
25761da177e4SLinus Torvalds 	case FSACTL_DELETE_DISK:
25771da177e4SLinus Torvalds 		return delete_disk(dev, arg);
25781da177e4SLinus Torvalds 	case FSACTL_FORCE_DELETE_DISK:
25791da177e4SLinus Torvalds 		return force_delete_disk(dev, arg);
25801da177e4SLinus Torvalds 	case FSACTL_GET_CONTAINERS:
25811da177e4SLinus Torvalds 		return aac_get_containers(dev);
25821da177e4SLinus Torvalds 	default:
25831da177e4SLinus Torvalds 		return -ENOTTY;
25841da177e4SLinus Torvalds 	}
25851da177e4SLinus Torvalds }
25861da177e4SLinus Torvalds 
25871da177e4SLinus Torvalds /**
25881da177e4SLinus Torvalds  *
25891da177e4SLinus Torvalds  * aac_srb_callback
25901da177e4SLinus Torvalds  * @context: the context set in the fib - here it is scsi cmd
25911da177e4SLinus Torvalds  * @fibptr: pointer to the fib
25921da177e4SLinus Torvalds  *
25931da177e4SLinus Torvalds  * Handles the completion of a scsi command to a non dasd device
25941da177e4SLinus Torvalds  *
25951da177e4SLinus Torvalds  */
25961da177e4SLinus Torvalds 
25971da177e4SLinus Torvalds static void aac_srb_callback(void *context, struct fib * fibptr)
25981da177e4SLinus Torvalds {
25991da177e4SLinus Torvalds 	struct aac_dev *dev;
26001da177e4SLinus Torvalds 	struct aac_srb_reply *srbreply;
26011da177e4SLinus Torvalds 	struct scsi_cmnd *scsicmd;
26021da177e4SLinus Torvalds 
26031da177e4SLinus Torvalds 	scsicmd = (struct scsi_cmnd *) context;
260403d44337SMark Haverkamp 
260503d44337SMark Haverkamp 	if (!aac_valid_context(scsicmd, fibptr))
260603d44337SMark Haverkamp 		return;
260703d44337SMark Haverkamp 
2608125e1874SEric Sesterhenn 	BUG_ON(fibptr == NULL);
26091da177e4SLinus Torvalds 
26101a655040SSalyzyn, Mark 	dev = fibptr->dev;
26111a655040SSalyzyn, Mark 
26121da177e4SLinus Torvalds 	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
26131da177e4SLinus Torvalds 
26141da177e4SLinus Torvalds 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
26151da177e4SLinus Torvalds 	/*
26161da177e4SLinus Torvalds 	 *	Calculate resid for sg
26171da177e4SLinus Torvalds 	 */
26181da177e4SLinus Torvalds 
2619727eead6SFUJITA Tomonori 	scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
2620727eead6SFUJITA Tomonori 		       - le32_to_cpu(srbreply->data_xfer_length));
26211da177e4SLinus Torvalds 
2622727eead6SFUJITA Tomonori 	scsi_dma_unmap(scsicmd);
26231da177e4SLinus Torvalds 
2624e3cc268fSRajashekhara, Mahesh 	/* expose physical device if expose_physicald flag is on */
2625e3cc268fSRajashekhara, Mahesh 	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
2626e3cc268fSRajashekhara, Mahesh 	  && expose_physicals > 0)
2627e3cc268fSRajashekhara, Mahesh 		aac_expose_phy_device(scsicmd);
2628e3cc268fSRajashekhara, Mahesh 
26291da177e4SLinus Torvalds 	/*
26301da177e4SLinus Torvalds 	 * First check the fib status
26311da177e4SLinus Torvalds 	 */
26321da177e4SLinus Torvalds 
26331da177e4SLinus Torvalds 	if (le32_to_cpu(srbreply->status) != ST_OK){
26341da177e4SLinus Torvalds 		int len;
26351da177e4SLinus Torvalds 		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
26363ace426fSSalyzyn, Mark 		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
26373ace426fSSalyzyn, Mark 			    SCSI_SENSE_BUFFERSIZE);
26381da177e4SLinus Torvalds 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
26391da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
26401da177e4SLinus Torvalds 	}
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds 	/*
26431da177e4SLinus Torvalds 	 * Next check the srb status
26441da177e4SLinus Torvalds 	 */
26451da177e4SLinus Torvalds 	switch( (le32_to_cpu(srbreply->srb_status))&0x3f){
26461da177e4SLinus Torvalds 	case SRB_STATUS_ERROR_RECOVERY:
26471da177e4SLinus Torvalds 	case SRB_STATUS_PENDING:
26481da177e4SLinus Torvalds 	case SRB_STATUS_SUCCESS:
26491da177e4SLinus Torvalds 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
26501da177e4SLinus Torvalds 		break;
26511da177e4SLinus Torvalds 	case SRB_STATUS_DATA_OVERRUN:
26521da177e4SLinus Torvalds 		switch(scsicmd->cmnd[0]){
26531da177e4SLinus Torvalds 		case  READ_6:
26541da177e4SLinus Torvalds 		case  WRITE_6:
26551da177e4SLinus Torvalds 		case  READ_10:
26561da177e4SLinus Torvalds 		case  WRITE_10:
26571da177e4SLinus Torvalds 		case  READ_12:
26581da177e4SLinus Torvalds 		case  WRITE_12:
26597a8cf29dSMark Haverkamp 		case  READ_16:
26607a8cf29dSMark Haverkamp 		case  WRITE_16:
26611da177e4SLinus Torvalds 			if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
26621da177e4SLinus Torvalds 				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
26631da177e4SLinus Torvalds 			} else {
26641da177e4SLinus Torvalds 				printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
26651da177e4SLinus Torvalds 			}
26661da177e4SLinus Torvalds 			scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
26671da177e4SLinus Torvalds 			break;
26681da177e4SLinus Torvalds 		case INQUIRY: {
26691da177e4SLinus Torvalds 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
26701da177e4SLinus Torvalds 			break;
26711da177e4SLinus Torvalds 		}
26721da177e4SLinus Torvalds 		default:
26731da177e4SLinus Torvalds 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
26741da177e4SLinus Torvalds 			break;
26751da177e4SLinus Torvalds 		}
26761da177e4SLinus Torvalds 		break;
26771da177e4SLinus Torvalds 	case SRB_STATUS_ABORTED:
26781da177e4SLinus Torvalds 		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
26791da177e4SLinus Torvalds 		break;
26801da177e4SLinus Torvalds 	case SRB_STATUS_ABORT_FAILED:
26811da177e4SLinus Torvalds 		// Not sure about this one - but assuming the hba was trying to abort for some reason
26821da177e4SLinus Torvalds 		scsicmd->result = DID_ERROR << 16 | ABORT << 8;
26831da177e4SLinus Torvalds 		break;
26841da177e4SLinus Torvalds 	case SRB_STATUS_PARITY_ERROR:
26851da177e4SLinus Torvalds 		scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8;
26861da177e4SLinus Torvalds 		break;
26871da177e4SLinus Torvalds 	case SRB_STATUS_NO_DEVICE:
26881da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_PATH_ID:
26891da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_TARGET_ID:
26901da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_LUN:
26911da177e4SLinus Torvalds 	case SRB_STATUS_SELECTION_TIMEOUT:
26921da177e4SLinus Torvalds 		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
26931da177e4SLinus Torvalds 		break;
26941da177e4SLinus Torvalds 
26951da177e4SLinus Torvalds 	case SRB_STATUS_COMMAND_TIMEOUT:
26961da177e4SLinus Torvalds 	case SRB_STATUS_TIMEOUT:
26971da177e4SLinus Torvalds 		scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8;
26981da177e4SLinus Torvalds 		break;
26991da177e4SLinus Torvalds 
27001da177e4SLinus Torvalds 	case SRB_STATUS_BUSY:
2701760af100SSalyzyn, Mark 		scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
27021da177e4SLinus Torvalds 		break;
27031da177e4SLinus Torvalds 
27041da177e4SLinus Torvalds 	case SRB_STATUS_BUS_RESET:
27051da177e4SLinus Torvalds 		scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8;
27061da177e4SLinus Torvalds 		break;
27071da177e4SLinus Torvalds 
27081da177e4SLinus Torvalds 	case SRB_STATUS_MESSAGE_REJECTED:
27091da177e4SLinus Torvalds 		scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
27101da177e4SLinus Torvalds 		break;
27111da177e4SLinus Torvalds 	case SRB_STATUS_REQUEST_FLUSHED:
27121da177e4SLinus Torvalds 	case SRB_STATUS_ERROR:
27131da177e4SLinus Torvalds 	case SRB_STATUS_INVALID_REQUEST:
27141da177e4SLinus Torvalds 	case SRB_STATUS_REQUEST_SENSE_FAILED:
27151da177e4SLinus Torvalds 	case SRB_STATUS_NO_HBA:
27161da177e4SLinus Torvalds 	case SRB_STATUS_UNEXPECTED_BUS_FREE:
27171da177e4SLinus Torvalds 	case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
27181da177e4SLinus Torvalds 	case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
27191da177e4SLinus Torvalds 	case SRB_STATUS_DELAYED_RETRY:
27201da177e4SLinus Torvalds 	case SRB_STATUS_BAD_FUNCTION:
27211da177e4SLinus Torvalds 	case SRB_STATUS_NOT_STARTED:
27221da177e4SLinus Torvalds 	case SRB_STATUS_NOT_IN_USE:
27231da177e4SLinus Torvalds 	case SRB_STATUS_FORCE_ABORT:
27241da177e4SLinus Torvalds 	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
27251da177e4SLinus Torvalds 	default:
27261da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
27271da177e4SLinus Torvalds 		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
27281da177e4SLinus Torvalds 			le32_to_cpu(srbreply->srb_status) & 0x3F,
27291da177e4SLinus Torvalds 			aac_get_status_string(
27301da177e4SLinus Torvalds 				le32_to_cpu(srbreply->srb_status) & 0x3F),
27311da177e4SLinus Torvalds 			scsicmd->cmnd[0],
27321da177e4SLinus Torvalds 			le32_to_cpu(srbreply->scsi_status));
27331da177e4SLinus Torvalds #endif
27341fc8010aSRajashekhara, Mahesh 		if ((scsicmd->cmnd[0] == ATA_12)
27351fc8010aSRajashekhara, Mahesh 		  || (scsicmd->cmnd[0] == ATA_16)) {
27361fc8010aSRajashekhara, Mahesh 			if (scsicmd->cmnd[2] & (0x01 << 5)) {
27371fc8010aSRajashekhara, Mahesh 				scsicmd->result = DID_OK << 16
27381fc8010aSRajashekhara, Mahesh 						| COMMAND_COMPLETE << 8;
27391da177e4SLinus Torvalds 				break;
27401fc8010aSRajashekhara, Mahesh 			} else {
27411fc8010aSRajashekhara, Mahesh 				scsicmd->result = DID_ERROR << 16
27421fc8010aSRajashekhara, Mahesh 						| COMMAND_COMPLETE << 8;
27431fc8010aSRajashekhara, Mahesh 				break;
27441fc8010aSRajashekhara, Mahesh 			}
27451fc8010aSRajashekhara, Mahesh 		} else {
27461fc8010aSRajashekhara, Mahesh 			scsicmd->result = DID_ERROR << 16
27471fc8010aSRajashekhara, Mahesh 					| COMMAND_COMPLETE << 8;
27481fc8010aSRajashekhara, Mahesh 			break;
27491fc8010aSRajashekhara, Mahesh 		}
27501da177e4SLinus Torvalds 	}
27518ce3eca4SSalyzyn, Mark 	if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
27521da177e4SLinus Torvalds 		int len;
27531da177e4SLinus Torvalds 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
27543ace426fSSalyzyn, Mark 		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
27553ace426fSSalyzyn, Mark 			    SCSI_SENSE_BUFFERSIZE);
27561da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
27577a8cf29dSMark Haverkamp 		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
27587a8cf29dSMark Haverkamp 					le32_to_cpu(srbreply->status), len);
27591da177e4SLinus Torvalds #endif
27601da177e4SLinus Torvalds 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
27611da177e4SLinus Torvalds 	}
27621da177e4SLinus Torvalds 	/*
27631da177e4SLinus Torvalds 	 * OR in the scsi status (already shifted up a bit)
27641da177e4SLinus Torvalds 	 */
27651da177e4SLinus Torvalds 	scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
27661da177e4SLinus Torvalds 
2767bfb35aa8SMark Haverkamp 	aac_fib_complete(fibptr);
2768bfb35aa8SMark Haverkamp 	aac_fib_free(fibptr);
27698e0c5ebdSMark Haverkamp 	scsicmd->scsi_done(scsicmd);
27701da177e4SLinus Torvalds }
27711da177e4SLinus Torvalds 
27721da177e4SLinus Torvalds /**
27731da177e4SLinus Torvalds  *
27741da177e4SLinus Torvalds  * aac_send_scb_fib
27751da177e4SLinus Torvalds  * @scsicmd: the scsi command block
27761da177e4SLinus Torvalds  *
27771da177e4SLinus Torvalds  * This routine will form a FIB and fill in the aac_srb from the
27781da177e4SLinus Torvalds  * scsicmd passed in.
27791da177e4SLinus Torvalds  */
27801da177e4SLinus Torvalds 
27811da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
27821da177e4SLinus Torvalds {
27831da177e4SLinus Torvalds 	struct fib* cmd_fibcontext;
27841da177e4SLinus Torvalds 	struct aac_dev* dev;
27851da177e4SLinus Torvalds 	int status;
27861da177e4SLinus Torvalds 
278784971738SMark Haverkamp 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
2788e5718774SMark Haverkamp 	if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
278984971738SMark Haverkamp 			scsicmd->device->lun > 7) {
27901da177e4SLinus Torvalds 		scsicmd->result = DID_NO_CONNECT << 16;
27911da177e4SLinus Torvalds 		scsicmd->scsi_done(scsicmd);
27921da177e4SLinus Torvalds 		return 0;
27931da177e4SLinus Torvalds 	}
27941da177e4SLinus Torvalds 
27951da177e4SLinus Torvalds 	/*
27961da177e4SLinus Torvalds 	 *	Allocate and initialize a Fib then setup a BlockWrite command
27971da177e4SLinus Torvalds 	 */
2798bfb35aa8SMark Haverkamp 	if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
27991da177e4SLinus Torvalds 		return -1;
28001da177e4SLinus Torvalds 	}
2801e8f32de5SMark Haverkamp 	status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
28021da177e4SLinus Torvalds 
28031da177e4SLinus Torvalds 	/*
28041da177e4SLinus Torvalds 	 *	Check that the command queued to the controller
28051da177e4SLinus Torvalds 	 */
28061da177e4SLinus Torvalds 	if (status == -EINPROGRESS) {
280777d644d4SMark Haverkamp 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
28081da177e4SLinus Torvalds 		return 0;
28091da177e4SLinus Torvalds 	}
28101da177e4SLinus Torvalds 
2811bfb35aa8SMark Haverkamp 	printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
2812bfb35aa8SMark Haverkamp 	aac_fib_complete(cmd_fibcontext);
2813bfb35aa8SMark Haverkamp 	aac_fib_free(cmd_fibcontext);
28141da177e4SLinus Torvalds 
28151da177e4SLinus Torvalds 	return -1;
28161da177e4SLinus Torvalds }
28171da177e4SLinus Torvalds 
28181da177e4SLinus Torvalds static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
28191da177e4SLinus Torvalds {
28201da177e4SLinus Torvalds 	struct aac_dev *dev;
28211da177e4SLinus Torvalds 	unsigned long byte_count = 0;
2822727eead6SFUJITA Tomonori 	int nseg;
28231da177e4SLinus Torvalds 
28241da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
28251da177e4SLinus Torvalds 	// Get rid of old data
28261da177e4SLinus Torvalds 	psg->count = 0;
28271da177e4SLinus Torvalds 	psg->sg[0].addr = 0;
28281da177e4SLinus Torvalds 	psg->sg[0].count = 0;
2829727eead6SFUJITA Tomonori 
2830727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
2831727eead6SFUJITA Tomonori 	BUG_ON(nseg < 0);
2832727eead6SFUJITA Tomonori 	if (nseg) {
28331da177e4SLinus Torvalds 		struct scatterlist *sg;
28341da177e4SLinus Torvalds 		int i;
28351da177e4SLinus Torvalds 
2836727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
28371da177e4SLinus Torvalds 
2838727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
28391da177e4SLinus Torvalds 			psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
28401da177e4SLinus Torvalds 			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
28411da177e4SLinus Torvalds 			byte_count += sg_dma_len(sg);
28421da177e4SLinus Torvalds 		}
28431da177e4SLinus Torvalds 		/* hba wants the size to be exact */
2844727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
284556b58712SMark Haverkamp  			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
2846727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
284756b58712SMark Haverkamp  			psg->sg[i-1].count = cpu_to_le32(temp);
2848727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
28491da177e4SLinus Torvalds 		}
28501da177e4SLinus Torvalds 		/* Check for command underflow */
28511da177e4SLinus Torvalds 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
28521da177e4SLinus Torvalds 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
28531da177e4SLinus Torvalds 					byte_count, scsicmd->underflow);
28541da177e4SLinus Torvalds 		}
28551da177e4SLinus Torvalds 	}
28561da177e4SLinus Torvalds 	return byte_count;
28571da177e4SLinus Torvalds }
28581da177e4SLinus Torvalds 
28591da177e4SLinus Torvalds 
28601da177e4SLinus Torvalds static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg)
28611da177e4SLinus Torvalds {
28621da177e4SLinus Torvalds 	struct aac_dev *dev;
28631da177e4SLinus Torvalds 	unsigned long byte_count = 0;
286456b58712SMark Haverkamp  	u64 addr;
2865727eead6SFUJITA Tomonori 	int nseg;
28661da177e4SLinus Torvalds 
28671da177e4SLinus Torvalds 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
28681da177e4SLinus Torvalds 	// Get rid of old data
28691da177e4SLinus Torvalds 	psg->count = 0;
28701da177e4SLinus Torvalds 	psg->sg[0].addr[0] = 0;
28711da177e4SLinus Torvalds 	psg->sg[0].addr[1] = 0;
28721da177e4SLinus Torvalds 	psg->sg[0].count = 0;
2873727eead6SFUJITA Tomonori 
2874727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
2875727eead6SFUJITA Tomonori 	BUG_ON(nseg < 0);
2876727eead6SFUJITA Tomonori 	if (nseg) {
28771da177e4SLinus Torvalds 		struct scatterlist *sg;
28781da177e4SLinus Torvalds 		int i;
28791da177e4SLinus Torvalds 
2880727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
28811241f359SMark Haverkamp 			int count = sg_dma_len(sg);
288256b58712SMark Haverkamp  			addr = sg_dma_address(sg);
288356b58712SMark Haverkamp  			psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
288456b58712SMark Haverkamp  			psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
28851241f359SMark Haverkamp 			psg->sg[i].count = cpu_to_le32(count);
28861241f359SMark Haverkamp 			byte_count += count;
28871da177e4SLinus Torvalds 		}
2888727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
28891da177e4SLinus Torvalds 		/* hba wants the size to be exact */
2890727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
289156b58712SMark Haverkamp  			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
2892727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
289356b58712SMark Haverkamp  			psg->sg[i-1].count = cpu_to_le32(temp);
2894727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
28951da177e4SLinus Torvalds 		}
28961da177e4SLinus Torvalds 		/* Check for command underflow */
28971da177e4SLinus Torvalds 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
28981da177e4SLinus Torvalds 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
28991da177e4SLinus Torvalds 					byte_count, scsicmd->underflow);
29001da177e4SLinus Torvalds 		}
29011da177e4SLinus Torvalds 	}
29021da177e4SLinus Torvalds 	return byte_count;
29031da177e4SLinus Torvalds }
29041da177e4SLinus Torvalds 
29050e68c003SMark Haverkamp static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
29060e68c003SMark Haverkamp {
29070e68c003SMark Haverkamp 	unsigned long byte_count = 0;
2908727eead6SFUJITA Tomonori 	int nseg;
29090e68c003SMark Haverkamp 
29100e68c003SMark Haverkamp 	// Get rid of old data
29110e68c003SMark Haverkamp 	psg->count = 0;
29120e68c003SMark Haverkamp 	psg->sg[0].next = 0;
29130e68c003SMark Haverkamp 	psg->sg[0].prev = 0;
29140e68c003SMark Haverkamp 	psg->sg[0].addr[0] = 0;
29150e68c003SMark Haverkamp 	psg->sg[0].addr[1] = 0;
29160e68c003SMark Haverkamp 	psg->sg[0].count = 0;
29170e68c003SMark Haverkamp 	psg->sg[0].flags = 0;
2918727eead6SFUJITA Tomonori 
2919727eead6SFUJITA Tomonori 	nseg = scsi_dma_map(scsicmd);
2920727eead6SFUJITA Tomonori 	BUG_ON(nseg < 0);
2921727eead6SFUJITA Tomonori 	if (nseg) {
29220e68c003SMark Haverkamp 		struct scatterlist *sg;
29230e68c003SMark Haverkamp 		int i;
29240e68c003SMark Haverkamp 
2925727eead6SFUJITA Tomonori 		scsi_for_each_sg(scsicmd, sg, nseg, i) {
29260e68c003SMark Haverkamp 			int count = sg_dma_len(sg);
29270e68c003SMark Haverkamp 			u64 addr = sg_dma_address(sg);
29280e68c003SMark Haverkamp 			psg->sg[i].next = 0;
29290e68c003SMark Haverkamp 			psg->sg[i].prev = 0;
29300e68c003SMark Haverkamp 			psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
29310e68c003SMark Haverkamp 			psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
29320e68c003SMark Haverkamp 			psg->sg[i].count = cpu_to_le32(count);
29330e68c003SMark Haverkamp 			psg->sg[i].flags = 0;
29340e68c003SMark Haverkamp 			byte_count += count;
29350e68c003SMark Haverkamp 		}
2936727eead6SFUJITA Tomonori 		psg->count = cpu_to_le32(nseg);
29370e68c003SMark Haverkamp 		/* hba wants the size to be exact */
2938727eead6SFUJITA Tomonori 		if (byte_count > scsi_bufflen(scsicmd)) {
29390e68c003SMark Haverkamp 			u32 temp = le32_to_cpu(psg->sg[i-1].count) -
2940727eead6SFUJITA Tomonori 				(byte_count - scsi_bufflen(scsicmd));
29410e68c003SMark Haverkamp 			psg->sg[i-1].count = cpu_to_le32(temp);
2942727eead6SFUJITA Tomonori 			byte_count = scsi_bufflen(scsicmd);
29430e68c003SMark Haverkamp 		}
29440e68c003SMark Haverkamp 		/* Check for command underflow */
29450e68c003SMark Haverkamp 		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
29460e68c003SMark Haverkamp 			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
29470e68c003SMark Haverkamp 					byte_count, scsicmd->underflow);
29480e68c003SMark Haverkamp 		}
29490e68c003SMark Haverkamp 	}
29500e68c003SMark Haverkamp 	return byte_count;
29510e68c003SMark Haverkamp }
29520e68c003SMark Haverkamp 
29531da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO
29541da177e4SLinus Torvalds 
29551da177e4SLinus Torvalds struct aac_srb_status_info {
29561da177e4SLinus Torvalds 	u32	status;
29571da177e4SLinus Torvalds 	char	*str;
29581da177e4SLinus Torvalds };
29591da177e4SLinus Torvalds 
29601da177e4SLinus Torvalds 
29611da177e4SLinus Torvalds static struct aac_srb_status_info srb_status_info[] = {
29621da177e4SLinus Torvalds 	{ SRB_STATUS_PENDING,		"Pending Status"},
29631da177e4SLinus Torvalds 	{ SRB_STATUS_SUCCESS,		"Success"},
29641da177e4SLinus Torvalds 	{ SRB_STATUS_ABORTED,		"Aborted Command"},
29651da177e4SLinus Torvalds 	{ SRB_STATUS_ABORT_FAILED,	"Abort Failed"},
29661da177e4SLinus Torvalds 	{ SRB_STATUS_ERROR,		"Error Event"},
29671da177e4SLinus Torvalds 	{ SRB_STATUS_BUSY,		"Device Busy"},
29681da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_REQUEST,	"Invalid Request"},
29691da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_PATH_ID,	"Invalid Path ID"},
29701da177e4SLinus Torvalds 	{ SRB_STATUS_NO_DEVICE,		"No Device"},
29711da177e4SLinus Torvalds 	{ SRB_STATUS_TIMEOUT,		"Timeout"},
29721da177e4SLinus Torvalds 	{ SRB_STATUS_SELECTION_TIMEOUT,	"Selection Timeout"},
29731da177e4SLinus Torvalds 	{ SRB_STATUS_COMMAND_TIMEOUT,	"Command Timeout"},
29741da177e4SLinus Torvalds 	{ SRB_STATUS_MESSAGE_REJECTED,	"Message Rejected"},
29751da177e4SLinus Torvalds 	{ SRB_STATUS_BUS_RESET,		"Bus Reset"},
29761da177e4SLinus Torvalds 	{ SRB_STATUS_PARITY_ERROR,	"Parity Error"},
29771da177e4SLinus Torvalds 	{ SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"},
29781da177e4SLinus Torvalds 	{ SRB_STATUS_NO_HBA,		"No HBA"},
29791da177e4SLinus Torvalds 	{ SRB_STATUS_DATA_OVERRUN,	"Data Overrun/Data Underrun"},
29801da177e4SLinus Torvalds 	{ SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"},
29811da177e4SLinus Torvalds 	{ SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"},
29821da177e4SLinus Torvalds 	{ SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
29831da177e4SLinus Torvalds 	{ SRB_STATUS_REQUEST_FLUSHED,	"Request Flushed"},
29841da177e4SLinus Torvalds 	{ SRB_STATUS_DELAYED_RETRY,	"Delayed Retry"},
29851da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_LUN,	"Invalid LUN"},
29861da177e4SLinus Torvalds 	{ SRB_STATUS_INVALID_TARGET_ID,	"Invalid TARGET ID"},
29871da177e4SLinus Torvalds 	{ SRB_STATUS_BAD_FUNCTION,	"Bad Function"},
29881da177e4SLinus Torvalds 	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
29891da177e4SLinus Torvalds 	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
29901da177e4SLinus Torvalds 	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
29911da177e4SLinus Torvalds 	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
29921da177e4SLinus Torvalds 	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
29931da177e4SLinus Torvalds 	{ 0xff,				"Unknown Error"}
29941da177e4SLinus Torvalds };
29951da177e4SLinus Torvalds 
29961da177e4SLinus Torvalds char *aac_get_status_string(u32 status)
29971da177e4SLinus Torvalds {
29981da177e4SLinus Torvalds 	int i;
29991da177e4SLinus Torvalds 
30006391a113STobias Klauser 	for (i = 0; i < ARRAY_SIZE(srb_status_info); i++)
30016391a113STobias Klauser 		if (srb_status_info[i].status == status)
30021da177e4SLinus Torvalds 			return srb_status_info[i].str;
30031da177e4SLinus Torvalds 
30041da177e4SLinus Torvalds 	return "Bad Status Code";
30051da177e4SLinus Torvalds }
30061da177e4SLinus Torvalds 
30071da177e4SLinus Torvalds #endif
3008