sbp2.c 81.6 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4
/*
 * sbp2.c - SBP-2 protocol driver for IEEE-1394
 *
 * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
Linus Torvalds's avatar
Linus Torvalds committed
5
 * jamesg@filanet.com (JSG)
Linus Torvalds's avatar
Linus Torvalds committed
6
 *
Ben Collins's avatar
Ben Collins committed
7 8
 * Copyright (C) 2003 Ben Collins <bcollins@debian.org>
 *
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
 * Brief Description:
 *
 * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394
 * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level
 * driver. It also registers as a SCSI lower-level driver in order to accept
 * SCSI commands for transport using SBP-2.
 *
32 33
 * You may access any attached SBP-2 storage devices as if they were SCSI
 * devices (e.g. mount /dev/sda1,  fdisk, mkfs, etc.).
Linus Torvalds's avatar
Linus Torvalds committed
34 35 36 37 38 39 40 41 42 43 44 45
 *
 * Current Issues:
 *
 *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
 *	  but the code needs additional debugging.
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/slab.h>
46
#include <linux/interrupt.h>
Linus Torvalds's avatar
Linus Torvalds committed
47 48 49
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/module.h>
50
#include <linux/moduleparam.h>
Linus Torvalds's avatar
Linus Torvalds committed
51 52 53
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/sched.h>
54
#include <linux/blkdev.h>
Linus Torvalds's avatar
Linus Torvalds committed
55
#include <linux/smp_lock.h>
Linus Torvalds's avatar
Linus Torvalds committed
56
#include <linux/init.h>
57 58
#include <linux/pci.h>

Linus Torvalds's avatar
Linus Torvalds committed
59 60 61 62
#include <asm/current.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/byteorder.h>
Ben Collins's avatar
Ben Collins committed
63
#include <asm/atomic.h>
Linus Torvalds's avatar
Linus Torvalds committed
64 65 66
#include <asm/system.h>
#include <asm/scatterlist.h>

Linus Torvalds's avatar
Linus Torvalds committed
67 68 69
#include "../scsi/scsi.h"
#include "../scsi/hosts.h"

70
#include "csr1212.h"
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
Ben Collins's avatar
Ben Collins committed
74
#include "nodemgr.h"
Linus Torvalds's avatar
Linus Torvalds committed
75 76 77 78 79
#include "hosts.h"
#include "highlevel.h"
#include "ieee1394_transactions.h"
#include "sbp2.h"

Ben Collins's avatar
Ben Collins committed
80
static char version[] __devinitdata =
Ben Collins's avatar
Ben Collins committed
81
	"$Rev: 1144 $ Ben Collins <bcollins@debian.org>";
Ben Collins's avatar
Ben Collins committed
82

Linus Torvalds's avatar
Linus Torvalds committed
83 84 85 86 87
/*
 * Module load parameter definitions
 */

/*
88
 * Change max_speed on module load if you have a bad IEEE-1394
89
 * controller that has trouble running 2KB packets at 400mb.
Linus Torvalds's avatar
Linus Torvalds committed
90
 *
Linus Torvalds's avatar
Linus Torvalds committed
91 92 93
 * NOTE: On certain OHCI parts I have seen short packets on async transmit
 * (probably due to PCI latency/throughput issues with the part). You can
 * bump down the speed if you are running into problems.
Ben Collins's avatar
Ben Collins committed
94
 */
Ben Collins's avatar
Ben Collins committed
95
static int max_speed = IEEE1394_SPEED_MAX;
96
module_param(max_speed, int, 0644);
97
MODULE_PARM_DESC(max_speed, "Force max speed (3 = 800mb, 2 = 400mb default, 1 = 200mb, 0 = 100mb)");
Ben Collins's avatar
Ben Collins committed
98 99

/*
100
 * Set serialize_io to 1 if you'd like only one scsi command sent
101 102
 * down to us at a time (debugging). This might be necessary for very
 * badly behaved sbp2 devices.
Ben Collins's avatar
Ben Collins committed
103
 */
104 105 106
static int serialize_io = 0;
module_param(serialize_io, int, 0444);
MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
Ben Collins's avatar
Ben Collins committed
107 108

/*
109
 * Bump up max_sectors if you'd like to support very large sized
110 111 112 113 114
 * transfers. Please note that some older sbp2 bridge chips are broken for
 * transfers greater or equal to 128KB.  Default is a value of 255
 * sectors, or just under 128KB (at 512 byte sector size). I can note that
 * the Oxsemi sbp2 chipsets have no problems supporting very large
 * transfer sizes.
Linus Torvalds's avatar
Linus Torvalds committed
115
 */
116 117 118
static int max_sectors = SBP2_MAX_SECTORS;
module_param(max_sectors, int, 0444);
MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = 255)");
Linus Torvalds's avatar
Linus Torvalds committed
119

Ben Collins's avatar
Ben Collins committed
120
/*
121 122 123 124 125
 * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
 * do an exclusive login, as it's generally unsafe to have two hosts
 * talking to a single sbp2 device at the same time (filesystem coherency,
 * etc.). If you're running an sbp2 device that supports multiple logins,
 * and you're either running read-only filesystems or some sort of special
126
 * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
127
 * see opengfs.sourceforge.net for more info), then set exclusive_login
128
 * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
Ben Collins's avatar
Ben Collins committed
129 130
 * concurrent logins.
 */
131 132 133
static int exclusive_login = 1;
module_param(exclusive_login, int, 0644);
MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)");
Ben Collins's avatar
Ben Collins committed
134

Ben Collins's avatar
Ben Collins committed
135
/*
136 137 138 139 140
 * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on
 * if your sbp2 device is not properly handling the SCSI inquiry command.
 * This hack makes the inquiry look more like a typical MS Windows
 * inquiry.
 * 
141
 * If force_inquiry_hack=1 is required for your device to work,
142 143
 * please submit the logged sbp2_firmware_revision value of this device to
 * the linux1394-devel mailing list.
Ben Collins's avatar
Ben Collins committed
144
 */
145 146 147
static int force_inquiry_hack = 0;
module_param(force_inquiry_hack, int, 0444);
MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
Ben Collins's avatar
Ben Collins committed
148

Linus Torvalds's avatar
Linus Torvalds committed
149 150

/*
Linus Torvalds's avatar
Linus Torvalds committed
151
 * Export information about protocols/devices supported by this driver.
Linus Torvalds's avatar
Linus Torvalds committed
152 153
 */
static struct ieee1394_device_id sbp2_id_table[] = {
Linus Torvalds's avatar
Linus Torvalds committed
154
	{
Ben Collins's avatar
Ben Collins committed
155
		.match_flags =IEEE1394_MATCH_SPECIFIER_ID |
Linus Torvalds's avatar
Linus Torvalds committed
156
		              IEEE1394_MATCH_VERSION,
Ben Collins's avatar
Ben Collins committed
157 158
		.specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
		.version =    SBP2_SW_VERSION_ENTRY & 0xffffff
Linus Torvalds's avatar
Linus Torvalds committed
159
	},
Linus Torvalds's avatar
Linus Torvalds committed
160 161 162
	{ }
};

Linus Torvalds's avatar
Linus Torvalds committed
163
MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
Linus Torvalds's avatar
Linus Torvalds committed
164

Linus Torvalds's avatar
Linus Torvalds committed
165
/*
Ben Collins's avatar
Ben Collins committed
166
 * Debug levels, configured via kernel config, or enable here.
Linus Torvalds's avatar
Linus Torvalds committed
167 168
 */

Ben Collins's avatar
Ben Collins committed
169 170 171 172
/* #define CONFIG_IEEE1394_SBP2_DEBUG_ORBS */
/* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */
/* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */
/* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */
Ben Collins's avatar
Ben Collins committed
173
/* #define CONFIG_IEEE1394_SBP2_PACKET_DUMP */
Ben Collins's avatar
Ben Collins committed
174

Linus Torvalds's avatar
Linus Torvalds committed
175
#ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
Linus Torvalds's avatar
Linus Torvalds committed
176
#define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
177
static u32 global_outstanding_command_orbs = 0;
Linus Torvalds's avatar
Linus Torvalds committed
178 179 180 181 182 183 184 185 186 187
#define outstanding_orb_incr global_outstanding_command_orbs++
#define outstanding_orb_decr global_outstanding_command_orbs--
#else
#define SBP2_ORB_DEBUG(fmt, args...)
#define outstanding_orb_incr
#define outstanding_orb_decr
#endif

#ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
#define SBP2_DMA_ALLOC(fmt, args...) \
Linus Torvalds's avatar
Linus Torvalds committed
188
	HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \
Linus Torvalds's avatar
Linus Torvalds committed
189 190
		 ++global_outstanding_dmas, ## args)
#define SBP2_DMA_FREE(fmt, args...) \
Linus Torvalds's avatar
Linus Torvalds committed
191
	HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \
Linus Torvalds's avatar
Linus Torvalds committed
192
		 --global_outstanding_dmas, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
193
static u32 global_outstanding_dmas = 0;
Linus Torvalds's avatar
Linus Torvalds committed
194 195 196 197 198 199
#else
#define SBP2_DMA_ALLOC(fmt, args...)
#define SBP2_DMA_FREE(fmt, args...)
#endif

#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
Linus Torvalds's avatar
Linus Torvalds committed
200 201 202 203
#define SBP2_DEBUG(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_INFO(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
204
#elif CONFIG_IEEE1394_SBP2_DEBUG == 1
Linus Torvalds's avatar
Linus Torvalds committed
205 206 207 208
#define SBP2_DEBUG(fmt, args...)	HPSB_DEBUG("sbp2: "fmt, ## args)
#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...)	HPSB_NOTICE("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...)		HPSB_WARN("sbp2: "fmt, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
209
#else 
Linus Torvalds's avatar
Linus Torvalds committed
210
#define SBP2_DEBUG(fmt, args...)
Ben Collins's avatar
Ben Collins committed
211 212 213
#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...)       HPSB_NOTICE("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...)         HPSB_WARN("sbp2: "fmt, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
214 215
#endif

Linus Torvalds's avatar
Linus Torvalds committed
216
#define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
Linus Torvalds's avatar
Linus Torvalds committed
217 218 219 220 221 222


/*
 * Globals
 */

223
static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id,
Ben Collins's avatar
Ben Collins committed
224 225
					   u32 status);

226
static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
Ben Collins's avatar
Ben Collins committed
227 228 229
				      u32 scsi_status, Scsi_Cmnd *SCpnt,
				      void (*done)(Scsi_Cmnd *));
	
Linus Torvalds's avatar
Linus Torvalds committed
230
static Scsi_Host_Template scsi_driver_template;
Linus Torvalds's avatar
Linus Torvalds committed
231

Ben Collins's avatar
Ben Collins committed
232 233
const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };

234 235 236
static void sbp2_remove_host(struct hpsb_host *host);
static void sbp2_host_reset(struct hpsb_host *host);

237 238
static struct hpsb_highlevel sbp2_highlevel = {
	.name =		SBP2_DEVICE_NAME,
Ben Collins's avatar
Ben Collins committed
239
	.remove_host =	sbp2_remove_host,
240
	.host_reset =	sbp2_host_reset,
Linus Torvalds's avatar
Linus Torvalds committed
241 242 243
};

static struct hpsb_address_ops sbp2_ops = {
Ben Collins's avatar
Ben Collins committed
244
	.write = sbp2_handle_status_write
Linus Torvalds's avatar
Linus Torvalds committed
245 246
};

Ben Collins's avatar
Ben Collins committed
247 248
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
static struct hpsb_address_ops sbp2_physdma_ops = {
Ben Collins's avatar
Ben Collins committed
249 250
        .read = sbp2_handle_physdma_read,
        .write = sbp2_handle_physdma_write,
Ben Collins's avatar
Ben Collins committed
251 252 253
};
#endif

Linus Torvalds's avatar
Linus Torvalds committed
254
static struct hpsb_protocol_driver sbp2_driver = {
255 256 257 258 259 260 261 262 263
	.name		= "SBP2 Driver",
	.id_table	= sbp2_id_table,
	.update		= sbp2_update,
	.driver		= {
		.name		= SBP2_DEVICE_NAME,
		.bus		= &ieee1394_bus_type,
		.probe		= sbp2_probe,
		.remove		= sbp2_remove,
	},
Linus Torvalds's avatar
Linus Torvalds committed
264
};
Linus Torvalds's avatar
Linus Torvalds committed
265

266

267
/* List of device firmware's that require a forced 36 byte inquiry.  */
Ben Collins's avatar
Ben Collins committed
268 269
static u32 sbp2_broken_inquiry_list[] = {
	0x00002800,	/* Stefan Richter <richtest@bauwesen.tu-cottbus.de> */
270 271 272
			/* DViCO Momobay CX-1 */
	0x00000200	/* Andreas Plesch <plesch@fas.harvard.edu> */
			/* QPS Fire DVDBurner */
Ben Collins's avatar
Ben Collins committed
273
};
Linus Torvalds's avatar
Linus Torvalds committed
274

275 276 277
#define NUM_BROKEN_INQUIRY_DEVS \
	(sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list))

Linus Torvalds's avatar
Linus Torvalds committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
/**************************************
 * General utility functions
 **************************************/


#ifndef __BIG_ENDIAN
/*
 * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
 */
static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
{
	u32 *temp = buffer;

	for (length = (length >> 2); length--; )
		temp[length] = be32_to_cpu(temp[length]);

	return;
}

/*
 * Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
 */
static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
{
	u32 *temp = buffer;

	for (length = (length >> 2); length--; )
		temp[length] = cpu_to_be32(temp[length]);

	return;
}
#else /* BIG_ENDIAN */
/* Why waste the cpu cycles? */
#define sbp2util_be32_to_cpu_buffer(x,y)
#define sbp2util_cpu_to_be32_buffer(x,y)
#endif

Ben Collins's avatar
Ben Collins committed
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
#ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP
/*
 * Debug packet dump routine. Length is in bytes.
 */
static void sbp2util_packet_dump(void *buffer, int length, char *dump_name, u32 dump_phys_addr)
{
	int i;
	unsigned char *dump = buffer;

	if (!dump || !length || !dump_name)
		return;

	if (dump_phys_addr)
		printk("[%s, 0x%x]", dump_name, dump_phys_addr);
	else
		printk("[%s]", dump_name);
	for (i = 0; i < length; i++) {
		if (i > 0x3f) {
			printk("\n   ...");
			break;
		}
		if ((i & 0x3) == 0)
			printk("  ");
		if ((i & 0xf) == 0)
			printk("\n   ");
		printk("%02x ", (int) dump[i]);
	}
	printk("\n");

	return;
}
#else
#define sbp2util_packet_dump(w,x,y,z)
#endif

/*
 * Goofy routine that basically does a down_timeout function.
 */
static int sbp2util_down_timeout(atomic_t *done, int timeout)
{
	int i;

	for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (schedule_timeout(HZ/10))	/* 100ms */
			return(1);
	}
	return ((i > 0) ? 0:1);
}

365 366
/* Free's an allocated packet */
static void sbp2_free_packet(struct hpsb_packet *packet)
Linus Torvalds's avatar
Linus Torvalds committed
367
{
368
	hpsb_free_tlabel(packet);
Ben Collins's avatar
Ben Collins committed
369
	hpsb_free_packet(packet);
Linus Torvalds's avatar
Linus Torvalds committed
370 371
}

Ben Collins's avatar
Ben Collins committed
372 373
/* This is much like hpsb_node_write(), except it ignores the response
 * subaction and returns immediately. Can be used from interrupts.
Linus Torvalds's avatar
Linus Torvalds committed
374
 */
Ben Collins's avatar
Ben Collins committed
375 376
int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
				quadlet_t *buffer, size_t length)
377
{
Linus Torvalds's avatar
Linus Torvalds committed
378 379
	struct hpsb_packet *packet;

Ben Collins's avatar
Ben Collins committed
380 381
	packet = hpsb_make_writepacket(ne->host, ne->nodeid,
				       addr, buffer, length);
382
        if (!packet)
Ben Collins's avatar
Ben Collins committed
383
                return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
384

385 386
	hpsb_set_packet_complete_task(packet, (void (*)(void*))sbp2_free_packet,
				      packet);
Linus Torvalds's avatar
Linus Torvalds committed
387

388
	hpsb_node_fill_packet(ne, packet);
Linus Torvalds's avatar
Linus Torvalds committed
389

Ben Collins's avatar
Ben Collins committed
390 391 392 393
        if (hpsb_send_packet(packet) < 0) {
		sbp2_free_packet(packet);
		return -EIO;
	}
Linus Torvalds's avatar
Linus Torvalds committed
394

Ben Collins's avatar
Ben Collins committed
395 396
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
397 398

/*
Linus Torvalds's avatar
Linus Torvalds committed
399 400
 * This function is called to create a pool of command orbs used for
 * command processing. It is called when a new sbp2 device is detected.
Linus Torvalds's avatar
Linus Torvalds committed
401
 */
402
static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id)
Linus Torvalds's avatar
Linus Torvalds committed
403
{
404
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
405
	int i;
406
	unsigned long flags, orbs;
Linus Torvalds's avatar
Linus Torvalds committed
407
	struct sbp2_command_info *command;
408

409
	orbs = serialize_io ? 2 : SBP2_MAX_CMDS;
Linus Torvalds's avatar
Linus Torvalds committed
410
        
Ben Collins's avatar
Ben Collins committed
411
	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
412
	for (i = 0; i < orbs; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
413
		command = (struct sbp2_command_info *)
414
		    kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC);
Linus Torvalds's avatar
Linus Torvalds committed
415
		if (!command) {
Ben Collins's avatar
Ben Collins committed
416
			spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
			return(-ENOMEM);
		}
		memset(command, '\0', sizeof(struct sbp2_command_info));
		command->command_orb_dma =
			pci_map_single (hi->host->pdev, &command->command_orb,
					sizeof(struct sbp2_command_orb),
					PCI_DMA_BIDIRECTIONAL);
		SBP2_DMA_ALLOC("single command orb DMA");
		command->sge_dma =
			pci_map_single (hi->host->pdev, &command->scatter_gather_element,
					sizeof(command->scatter_gather_element),
					PCI_DMA_BIDIRECTIONAL);
		SBP2_DMA_ALLOC("scatter_gather_element");
		INIT_LIST_HEAD(&command->list);
		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
	}
Ben Collins's avatar
Ben Collins committed
433
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
434 435 436 437 438 439
	return 0;
}

/*
 * This function is called to delete a pool of command orbs.
 */
440
static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id)
Linus Torvalds's avatar
Linus Torvalds committed
441
{
442
	struct hpsb_host *host = scsi_id->hi->host;
Linus Torvalds's avatar
Linus Torvalds committed
443
	struct list_head *lh, *next;
Linus Torvalds's avatar
Linus Torvalds committed
444 445 446
	struct sbp2_command_info *command;
	unsigned long flags;
        
Ben Collins's avatar
Ben Collins committed
447
	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
448
	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
Linus Torvalds's avatar
Linus Torvalds committed
449
		list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) {
Linus Torvalds's avatar
Linus Torvalds committed
450 451 452
			command = list_entry(lh, struct sbp2_command_info, list);

			/* Release our generic DMA's */
453
			pci_unmap_single(host->pdev, command->command_orb_dma,
Linus Torvalds's avatar
Linus Torvalds committed
454 455 456
					 sizeof(struct sbp2_command_orb),
					 PCI_DMA_BIDIRECTIONAL);
			SBP2_DMA_FREE("single command orb DMA");
457
			pci_unmap_single(host->pdev, command->sge_dma,
Linus Torvalds's avatar
Linus Torvalds committed
458 459 460 461 462 463 464
					 sizeof(command->scatter_gather_element),
					 PCI_DMA_BIDIRECTIONAL);
			SBP2_DMA_FREE("scatter_gather_element");

			kfree(command);
		}
	}
Ben Collins's avatar
Ben Collins committed
465
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
466 467 468 469
	return;
}

/* 
Ben Collins's avatar
Ben Collins committed
470 471
 * This function finds the sbp2_command for a given outstanding command
 * orb.Only looks at the inuse list.
Linus Torvalds's avatar
Linus Torvalds committed
472
 */
Linus Torvalds's avatar
Linus Torvalds committed
473 474
static struct sbp2_command_info *sbp2util_find_command_for_orb(
		struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
Linus Torvalds's avatar
Linus Torvalds committed
475 476 477 478
{
	struct sbp2_command_info *command;
	unsigned long flags;

Ben Collins's avatar
Ben Collins committed
479
	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
480
	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
481
		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
Linus Torvalds's avatar
Linus Torvalds committed
482
			if (command->command_orb_dma == orb) {
Ben Collins's avatar
Ben Collins committed
483
				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
484 485 486 487
				return (command);
			}
		}
	}
Ben Collins's avatar
Ben Collins committed
488
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
489 490 491 492 493 494 495

	SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb);

	return(NULL);
}

/* 
Ben Collins's avatar
Ben Collins committed
496
 * This function finds the sbp2_command for a given outstanding SCpnt.
Linus Torvalds's avatar
Linus Torvalds committed
497
 * Only looks at the inuse list.
Linus Torvalds's avatar
Linus Torvalds committed
498 499 500 501 502 503
 */
static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
{
	struct sbp2_command_info *command;
	unsigned long flags;

Ben Collins's avatar
Ben Collins committed
504
	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
505
	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
506
		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
Linus Torvalds's avatar
Linus Torvalds committed
507
			if (command->Current_SCpnt == SCpnt) {
Ben Collins's avatar
Ben Collins committed
508
				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
509 510 511 512
				return (command);
			}
		}
	}
Ben Collins's avatar
Ben Collins committed
513
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
514 515 516 517 518 519
	return(NULL);
}

/*
 * This function allocates a command orb used to send a scsi command.
 */
Linus Torvalds's avatar
Linus Torvalds committed
520 521 522
static struct sbp2_command_info *sbp2util_allocate_command_orb(
		struct scsi_id_instance_data *scsi_id, 
		Scsi_Cmnd *Current_SCpnt, 
523
		void (*Current_done)(Scsi_Cmnd *))
Linus Torvalds's avatar
Linus Torvalds committed
524 525 526 527 528
{
	struct list_head *lh;
	struct sbp2_command_info *command = NULL;
	unsigned long flags;

Ben Collins's avatar
Ben Collins committed
529
	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
530 531 532 533 534 535 536 537
	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
		lh = scsi_id->sbp2_command_orb_completed.next;
		list_del(lh);
		command = list_entry(lh, struct sbp2_command_info, list);
		command->Current_done = Current_done;
		command->Current_SCpnt = Current_SCpnt;
		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
538
		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
Linus Torvalds's avatar
Linus Torvalds committed
539
	}
Ben Collins's avatar
Ben Collins committed
540
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543 544 545 546
	return (command);
}

/* Free our DMA's */
static void sbp2util_free_command_dma(struct sbp2_command_info *command)
{
547 548
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)command->Current_SCpnt->device->host->hostdata[0];
549
	struct hpsb_host *host;
Linus Torvalds's avatar
Linus Torvalds committed
550

551 552
	if (!scsi_id) {
		printk(KERN_ERR "%s: scsi_id == NULL\n", __FUNCTION__);
Linus Torvalds's avatar
Linus Torvalds committed
553 554 555
		return;
	}

556 557
	host = scsi_id->ud->ne->host;

Linus Torvalds's avatar
Linus Torvalds committed
558
	if (command->cmd_dma) {
Linus Torvalds's avatar
Linus Torvalds committed
559
		if (command->dma_type == CMD_DMA_SINGLE) {
560
			pci_unmap_single(host->pdev, command->cmd_dma,
Linus Torvalds's avatar
Linus Torvalds committed
561 562 563
					 command->dma_size, command->dma_dir);
			SBP2_DMA_FREE("single bulk");
		} else if (command->dma_type == CMD_DMA_PAGE) {
564
			pci_unmap_page(host->pdev, command->cmd_dma,
Linus Torvalds's avatar
Linus Torvalds committed
565 566 567 568
				       command->dma_size, command->dma_dir);
			SBP2_DMA_FREE("single page");
		} /* XXX: Check for CMD_DMA_NONE bug */
		command->dma_type = CMD_DMA_NONE;
Linus Torvalds's avatar
Linus Torvalds committed
569 570 571 572
		command->cmd_dma = 0;
	}

	if (command->sge_buffer) {
573
		pci_unmap_sg(host->pdev, command->sge_buffer,
Linus Torvalds's avatar
Linus Torvalds committed
574 575 576 577 578 579 580 581 582 583 584 585 586
			     command->dma_size, command->dma_dir);
		SBP2_DMA_FREE("scatter list");
		command->sge_buffer = NULL;
	}
}

/*
 * This function moves a command to the completed orb list.
 */
static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command)
{
	unsigned long flags;

Ben Collins's avatar
Ben Collins committed
587
	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
588 589 590
	list_del(&command->list);
	sbp2util_free_command_dma(command);
	list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
Ben Collins's avatar
Ben Collins committed
591
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
592 593
}

Linus Torvalds's avatar
Linus Torvalds committed
594 595


Linus Torvalds's avatar
Linus Torvalds committed
596 597 598
/*********************************************
 * IEEE-1394 core driver stack related section
 *********************************************/
599
static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud);
Linus Torvalds's avatar
Linus Torvalds committed
600

601
static int sbp2_probe(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
602
{
603
	struct unit_directory *ud;
604
	struct scsi_id_instance_data *scsi_id;
Linus Torvalds's avatar
Linus Torvalds committed
605

606
	SBP2_DEBUG("sbp2_probe");
607 608 609

	ud = container_of(dev, struct unit_directory, device);

610 611 612 613 614
	/* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)
	 * instead. */
	if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY)
		return -ENODEV;

615
        scsi_id = sbp2_alloc_device(ud);
616

617 618 619 620
        if (!scsi_id)
                return -ENOMEM;

        sbp2_parse_unit_directory(scsi_id, ud);
Linus Torvalds's avatar
Linus Torvalds committed
621

622
        return sbp2_start_device(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
623
}
Linus Torvalds's avatar
Linus Torvalds committed
624

625
static int sbp2_remove(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
626
{
627 628 629
	struct unit_directory *ud;
	struct scsi_id_instance_data *scsi_id;

630
	SBP2_DEBUG("sbp2_remove");
Linus Torvalds's avatar
Linus Torvalds committed
631

632
	ud = container_of(dev, struct unit_directory, device);
633
	scsi_id = ud->device.driver_data;
Ben Collins's avatar
Ben Collins committed
634

635 636
	sbp2_logout_device(scsi_id);
	sbp2_remove_device(scsi_id);
Ben Collins's avatar
Ben Collins committed
637

638
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
639 640 641 642
}

static void sbp2_update(struct unit_directory *ud)
{
643 644
	struct scsi_id_instance_data *scsi_id = ud->device.driver_data;
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
645

Linus Torvalds's avatar
Linus Torvalds committed
646
	SBP2_DEBUG("sbp2_update");
Linus Torvalds's avatar
Linus Torvalds committed
647

648
	hi = scsi_id->hi;
Ben Collins's avatar
Ben Collins committed
649

650
	if (sbp2_reconnect_device(scsi_id)) {
Linus Torvalds's avatar
Linus Torvalds committed
651
		
652 653 654 655 656
		/* 
		 * Ok, reconnect has failed. Perhaps we didn't
		 * reconnect fast enough. Try doing a regular login.
		 */
		sbp2_logout_device(scsi_id);
657

658 659 660 661 662
		if (sbp2_login_device(scsi_id)) {
			/* Login failed too, just remove the device. */
			SBP2_ERR("sbp2_reconnect_device failed!");
			sbp2_remove_device(scsi_id);
			return;
Linus Torvalds's avatar
Linus Torvalds committed
663
		}
664
	}
Linus Torvalds's avatar
Linus Torvalds committed
665

666 667
	/* Set max retries to something large on the device. */
	sbp2_set_busy_timeout(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
668

669 670
	/* Do a SBP-2 fetch agent reset. */
	sbp2_agent_reset(scsi_id, 1);
Linus Torvalds's avatar
Linus Torvalds committed
671

672 673 674 675 676 677 678
	/* Get the max speed and packet size that we can use. */
	sbp2_max_speed_and_size(scsi_id);

	/* Complete any pending commands with busy (so they get
	 * retried) and remove them from our queue
	 */
	sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
Linus Torvalds's avatar
Linus Torvalds committed
679
}
Linus Torvalds's avatar
Linus Torvalds committed
680

681 682 683
/* This functions is called by the sbp2_probe, for each new device. We now
 * allocate one scsi host for each scsi_id (unit directory). */
static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud)
Linus Torvalds's avatar
Linus Torvalds committed
684 685
{
	struct sbp2scsi_host_info *hi;
686 687
	struct Scsi_Host *scsi_host = NULL;
	struct scsi_id_instance_data *scsi_id = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
688

689
	SBP2_DEBUG("sbp2_alloc_device");
690

691 692 693 694
	scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL);
	if (!scsi_id) {
		SBP2_ERR("failed to create scsi_id");
		goto failed_alloc;
Linus Torvalds's avatar
Linus Torvalds committed
695
	}
696
	memset(scsi_id, 0, sizeof(*scsi_id));
Linus Torvalds's avatar
Linus Torvalds committed
697

698 699 700 701 702 703 704 705 706 707
	scsi_id->ne = ud->ne;
	scsi_id->ud = ud;
	scsi_id->speed_code = IEEE1394_SPEED_100;
	scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
	atomic_set(&scsi_id->sbp2_login_complete, 0);
	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
	INIT_LIST_HEAD(&scsi_id->scsi_list);
	scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
	scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;
708

709
	ud->device.driver_data = scsi_id;
710

711
	hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
712
	if (!hi) {
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
		hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host, sizeof(*hi));
		if (!hi) {
			SBP2_ERR("failed to allocate hostinfo");
			goto failed_alloc;
		}
		SBP2_DEBUG("sbp2_alloc_device: allocated hostinfo");
		hi->host = ud->ne->host;
		INIT_LIST_HEAD(&hi->scsi_ids);

		/* Register our sbp2 status address space... */
		hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_ops,
					SBP2_STATUS_FIFO_ADDRESS,
					SBP2_STATUS_FIFO_ADDRESS +
					SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2_MAX_UDS_PER_NODE+1));
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
		/* Handle data movement if physical dma is not
		 * enabled/supportedon host controller */
		hpsb_register_addrspace(&sbp2_highlevel, host, &sbp2_physdma_ops,
					0x0ULL, 0xfffffffcULL);
#endif
733 734
	}

735
	scsi_id->hi = hi;
Ben Collins's avatar
Ben Collins committed
736

737
	list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids);
Linus Torvalds's avatar
Linus Torvalds committed
738

739 740 741 742 743
	/* Register our host with the SCSI stack. */
	scsi_host = scsi_host_alloc(&scsi_driver_template, 0);
	if (!scsi_host) {
		SBP2_ERR("failed to register scsi host");
		goto failed_alloc;
Ben Collins's avatar
Ben Collins committed
744
	}
Linus Torvalds's avatar
Linus Torvalds committed
745

746 747 748 749 750 751 752 753 754 755 756 757 758
	scsi_host->hostdata[0] = (unsigned long)scsi_id;

	if (!scsi_add_host(scsi_host, &ud->device)) {
		scsi_id->scsi_host = scsi_host;
		return scsi_id;
	}

	SBP2_ERR("failed to add scsi host");
	scsi_host_put(scsi_host);

failed_alloc:
	sbp2_remove_device(scsi_id);
	return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
759 760 761
}


762
static void sbp2_host_reset(struct hpsb_host *host)
Linus Torvalds's avatar
Linus Torvalds committed
763 764
{
	struct sbp2scsi_host_info *hi;
765
	struct scsi_id_instance_data *scsi_id;
Linus Torvalds's avatar
Linus Torvalds committed
766

767
	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
Ben Collins's avatar
Ben Collins committed
768 769

	if (hi) {
770 771
		list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
			scsi_block_requests(scsi_id->scsi_host);
772
	}
Linus Torvalds's avatar
Linus Torvalds committed
773 774
}

Ben Collins's avatar
Ben Collins committed
775

776
static void sbp2_remove_host(struct hpsb_host *host)
777 778 779
{
	struct sbp2scsi_host_info *hi;

780 781
	SBP2_DEBUG("sbp2_remove_host");

782 783
	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);

784 785 786 787 788 789 790 791 792
	if (hi) {
		struct scsi_id_instance_data *scsi_id;

		list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list) {
			down_write(&scsi_id->ud->device.bus->subsys.rwsem);
			device_release_driver(&scsi_id->ud->device);
			up_write(&scsi_id->ud->device.bus->subsys.rwsem);
		}
	}
793 794 795
}


Linus Torvalds's avatar
Linus Torvalds committed
796
/*
Linus Torvalds's avatar
Linus Torvalds committed
797 798
 * This function is where we first pull the node unique ids, and then
 * allocate memory and register a SBP-2 device.
Linus Torvalds's avatar
Linus Torvalds committed
799
 */
Ben Collins's avatar
Ben Collins committed
800
static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
Linus Torvalds's avatar
Linus Torvalds committed
801
{
Ben Collins's avatar
Ben Collins committed
802
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Ben Collins's avatar
Ben Collins committed
803
	struct scsi_device *sdev;
Linus Torvalds's avatar
Linus Torvalds committed
804

Linus Torvalds's avatar
Linus Torvalds committed
805
	SBP2_DEBUG("sbp2_start_device");
806

Linus Torvalds's avatar
Linus Torvalds committed
807 808 809 810 811 812 813 814
	/* Login FIFO DMA */
	scsi_id->login_response =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_response),
				     &scsi_id->login_response_dma);
	if (!scsi_id->login_response)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for login FIFO");

815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
	/* Query logins ORB DMA */
	scsi_id->query_logins_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb),
				     &scsi_id->query_logins_orb_dma);
	if (!scsi_id->query_logins_orb)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for query logins ORB");

	/* Query logins response DMA */
	scsi_id->query_logins_response =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response),
				     &scsi_id->query_logins_response_dma);
	if (!scsi_id->query_logins_response)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for query logins response");

Linus Torvalds's avatar
Linus Torvalds committed
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
	/* Reconnect ORB DMA */
	scsi_id->reconnect_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb),
				     &scsi_id->reconnect_orb_dma);
	if (!scsi_id->reconnect_orb)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for reconnect ORB");

	/* Logout ORB DMA */
	scsi_id->logout_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb),
				     &scsi_id->logout_orb_dma);
	if (!scsi_id->logout_orb)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for logout ORB");

	/* Login ORB DMA */
	scsi_id->login_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb),
				     &scsi_id->login_orb_dma);
851
	if (!scsi_id->login_orb) {
Linus Torvalds's avatar
Linus Torvalds committed
852
alloc_fail:
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
		if (scsi_id->query_logins_response) {
			pci_free_consistent(hi->host->pdev,
					    sizeof(struct sbp2_query_logins_response),
					    scsi_id->query_logins_response,
					    scsi_id->query_logins_response_dma);
			SBP2_DMA_FREE("query logins response DMA");
		}

		if (scsi_id->query_logins_orb) {
			pci_free_consistent(hi->host->pdev,
					    sizeof(struct sbp2_query_logins_orb),
					    scsi_id->query_logins_orb,
					    scsi_id->query_logins_orb_dma);
			SBP2_DMA_FREE("query logins ORB DMA");
		}
	
Linus Torvalds's avatar
Linus Torvalds committed
869 870 871 872 873 874 875 876
		if (scsi_id->logout_orb) {
			pci_free_consistent(hi->host->pdev,
					sizeof(struct sbp2_logout_orb),
					scsi_id->logout_orb,
					scsi_id->logout_orb_dma);
			SBP2_DMA_FREE("logout ORB DMA");
		}

Linus Torvalds's avatar
Linus Torvalds committed
877 878 879 880 881 882 883 884 885 886 887 888 889 890
		if (scsi_id->reconnect_orb) {
			pci_free_consistent(hi->host->pdev,
					sizeof(struct sbp2_reconnect_orb),
					scsi_id->reconnect_orb,
					scsi_id->reconnect_orb_dma);
			SBP2_DMA_FREE("reconnect ORB DMA");
		}

		if (scsi_id->login_response) {
			pci_free_consistent(hi->host->pdev,
					sizeof(struct sbp2_login_response),
					scsi_id->login_response,
					scsi_id->login_response_dma);
			SBP2_DMA_FREE("login FIFO DMA");
Linus Torvalds's avatar
Linus Torvalds committed
891
		}
Linus Torvalds's avatar
Linus Torvalds committed
892 893

		kfree(scsi_id);
Ben Collins's avatar
Ben Collins committed
894

895
		list_del(&scsi_id->scsi_list);
Ben Collins's avatar
Ben Collins committed
896

Linus Torvalds's avatar
Linus Torvalds committed
897
		SBP2_ERR ("Could not allocate memory for scsi_id");
898 899

		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
900
	}
Linus Torvalds's avatar
Linus Torvalds committed
901
	SBP2_DMA_ALLOC("consistent DMA region for login ORB");
Linus Torvalds's avatar
Linus Torvalds committed
902

903
	SBP2_DEBUG("New SBP-2 device inserted, SCSI ID = %x", scsi_id->ud->id);
Linus Torvalds's avatar
Linus Torvalds committed
904 905

	/*
Linus Torvalds's avatar
Linus Torvalds committed
906
	 * Create our command orb pool
Linus Torvalds's avatar
Linus Torvalds committed
907
	 */
908
	if (sbp2util_create_command_orb_pool(scsi_id)) {
Linus Torvalds's avatar
Linus Torvalds committed
909
		SBP2_ERR("sbp2util_create_command_orb_pool failed!");
910
		sbp2_remove_device(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
911
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
912 913
	}

914 915 916 917 918 919 920 921 922 923
	/* Schedule a timeout here. The reason is that we may be so close
	 * to a bus reset, that the device is not available for logins.
	 * This can happen when the bus reset is caused by the host
	 * connected to the sbp2 device being removed. That host would
	 * have a certain amount of time to relogin before the sbp2 device
	 * allows someone else to login instead. One second makes sense. */
	set_current_state(TASK_INTERRUPTIBLE);
	schedule_timeout(HZ);
						

Linus Torvalds's avatar
Linus Torvalds committed
924
	/*
Linus Torvalds's avatar
Linus Torvalds committed
925
	 * Login to the sbp-2 device
Linus Torvalds's avatar
Linus Torvalds committed
926
	 */
927
	if (sbp2_login_device(scsi_id)) {
Linus Torvalds's avatar
Linus Torvalds committed
928
		/* Login failed, just remove the device. */
929
		sbp2_remove_device(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
930
		return -EBUSY;
Linus Torvalds's avatar
Linus Torvalds committed
931 932
	}

Linus Torvalds's avatar
Linus Torvalds committed
933 934 935
	/*
	 * Set max retries to something large on the device
	 */
936
	sbp2_set_busy_timeout(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
937 938 939 940
	
	/*
	 * Do a SBP-2 fetch agent reset
	 */
941
	sbp2_agent_reset(scsi_id, 1);
Linus Torvalds's avatar
Linus Torvalds committed
942 943 944 945
	
	/*
	 * Get the max speed and packet size that we can use
	 */
946
	sbp2_max_speed_and_size(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
947

Ben Collins's avatar
Ben Collins committed
948
	/* Add this device to the scsi layer now */
949
	sdev = scsi_add_device(scsi_id->scsi_host, 0, scsi_id->ud->id, 0);
Ben Collins's avatar
Ben Collins committed
950 951 952 953 954
	if (IS_ERR(sdev)) {
		SBP2_ERR("scsi_add_device failed");
		return PTR_ERR(sdev);
	}

Linus Torvalds's avatar
Linus Torvalds committed
955
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
956 957 958
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
959
 * This function removes an sbp2 device from the sbp2scsi_host_info struct.
Linus Torvalds's avatar
Linus Torvalds committed
960
 */
961
static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
Linus Torvalds's avatar
Linus Torvalds committed
962
{
963
	struct sbp2scsi_host_info *hi;
Ben Collins's avatar
Ben Collins committed
964

Linus Torvalds's avatar
Linus Torvalds committed
965 966
	SBP2_DEBUG("sbp2_remove_device");

967 968 969 970
	if (!scsi_id)
		return;

	hi = scsi_id->hi;
Ben Collins's avatar
Ben Collins committed
971

972 973 974 975
	/* This will remove our scsi device aswell */
	if (scsi_id->scsi_host) {
		scsi_remove_host(scsi_id->scsi_host);
		scsi_host_put(scsi_id->scsi_host);
976
	}
Ben Collins's avatar
Ben Collins committed
977

978
	sbp2util_remove_command_orb_pool(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
979

980
	list_del(&scsi_id->scsi_list);
Ben Collins's avatar
Ben Collins committed
981

Linus Torvalds's avatar
Linus Torvalds committed
982 983 984 985 986 987 988
	if (scsi_id->login_response) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_login_response),
				    scsi_id->login_response,
				    scsi_id->login_response_dma);
		SBP2_DMA_FREE("single login FIFO");
	}
Linus Torvalds's avatar
Linus Torvalds committed
989

Linus Torvalds's avatar
Linus Torvalds committed
990 991 992 993 994 995
	if (scsi_id->login_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_login_orb),
				    scsi_id->login_orb,
				    scsi_id->login_orb_dma);
		SBP2_DMA_FREE("single login ORB");
Linus Torvalds's avatar
Linus Torvalds committed
996 997
	}

Linus Torvalds's avatar
Linus Torvalds committed
998 999 1000 1001 1002 1003 1004
	if (scsi_id->reconnect_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_reconnect_orb),
				    scsi_id->reconnect_orb,
				    scsi_id->reconnect_orb_dma);
		SBP2_DMA_FREE("single reconnect orb");
	}
Linus Torvalds's avatar
Linus Torvalds committed
1005

Linus Torvalds's avatar
Linus Torvalds committed
1006 1007 1008 1009
	if (scsi_id->logout_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_logout_orb),
				    scsi_id->logout_orb,
1010
				    scsi_id->logout_orb_dma);
Linus Torvalds's avatar
Linus Torvalds committed
1011 1012
		SBP2_DMA_FREE("single logout orb");
	}
Linus Torvalds's avatar
Linus Torvalds committed
1013

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
	if (scsi_id->query_logins_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_query_logins_orb),
				    scsi_id->query_logins_orb,
				    scsi_id->query_logins_orb_dma);
		SBP2_DMA_FREE("single query logins orb");
	}

	if (scsi_id->query_logins_response) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_query_logins_response),
				    scsi_id->query_logins_response,
				    scsi_id->query_logins_response_dma);
		SBP2_DMA_FREE("single query logins data");
	}

1030
	scsi_id->ud->device.driver_data = NULL;
Ben Collins's avatar
Ben Collins committed
1031

1032
	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->ud->id);
Ben Collins's avatar
Ben Collins committed
1033

Linus Torvalds's avatar
Linus Torvalds committed
1034
	kfree(scsi_id);
Linus Torvalds's avatar
Linus Torvalds committed
1035 1036
}

Ben Collins's avatar
Ben Collins committed
1037 1038 1039 1040 1041 1042
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/*
 * This function deals with physical dma write requests (for adapters that do not support
 * physical dma in hardware). Mostly just here for debugging...
 */
static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
1043
                                     u64 addr, size_t length, u16 flags)
Ben Collins's avatar
Ben Collins committed
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
{

        /*
         * Manually put the data in the right place.
         */
        memcpy(bus_to_virt((u32)addr), data, length);
	sbp2util_packet_dump(data, length, "sbp2 phys dma write by device", (u32)addr);
        return(RCODE_COMPLETE);
}

/*
 * This function deals with physical dma read requests (for adapters that do not support
 * physical dma in hardware). Mostly just here for debugging...
 */
static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
1059
                                    u64 addr, size_t length, u16 flags)
Ben Collins's avatar
Ben Collins committed
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
{

        /*
         * Grab data from memory and send a read response.
         */
        memcpy(data, bus_to_virt((u32)addr), length);
	sbp2util_packet_dump(data, length, "sbp2 phys dma read by device", (u32)addr);
        return(RCODE_COMPLETE);
}
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1071 1072 1073 1074 1075

/**************************************
 * SBP-2 protocol related section
 **************************************/

Ben Collins's avatar
Ben Collins committed
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
/*
 * This function determines if we should convert scsi commands for a particular sbp2 device type
 */
static __inline__ int sbp2_command_conversion_device_type(u8 device_type)
{
	return (((device_type == TYPE_DISK) ||
		 (device_type == TYPE_SDAD) ||
		 (device_type == TYPE_ROM)) ? 1:0);
}

1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
/*
 * This function queries the device for the maximum concurrent logins it
 * supports.
 */
static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	quadlet_t data[2];
	int max_logins;
	int active_logins;

	SBP2_DEBUG("sbp2_query_logins");

	scsi_id->query_logins_orb->reserved1 = 0x0;
	scsi_id->query_logins_orb->reserved2 = 0x0;

	scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma;
	scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
	SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized");

	scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(QUERY_LOGINS_REQUEST);
	scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
		scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
Ben Collins's avatar
Ben Collins committed
1110 1111
		SBP2_DEBUG("sbp2_query_logins: set lun to %d",
			   ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun));
1112 1113 1114 1115 1116 1117 1118 1119
	}
	SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");

	scsi_id->query_logins_orb->reserved_resp_length =
		ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
	SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");

	scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
1120
						    SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
1121 1122 1123 1124 1125 1126 1127 1128
	scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
						     SBP2_STATUS_FIFO_ADDRESS_HI);
	SBP2_DEBUG("sbp2_query_logins: status FIFO initialized");

	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));

	SBP2_DEBUG("sbp2_query_logins: orb byte-swapped");

1129
	sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb),
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
			     "sbp2 query logins orb", scsi_id->query_logins_orb_dma);

	memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset");

	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->query_logins_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	atomic_set(&scsi_id->sbp2_login_complete, 0);

	SBP2_DEBUG("sbp2_query_logins: prepared to write");
	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
	SBP2_DEBUG("sbp2_query_logins: written");

	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
		SBP2_ERR("Error querying logins to SBP-2 device - timed out");
		return(-EIO);
	}

	if (scsi_id->status_block.ORB_offset_lo != scsi_id->query_logins_orb_dma) {
		SBP2_ERR("Error querying logins to SBP-2 device - timed out");
		return(-EIO);
	}

	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {

		SBP2_ERR("Error querying logins to SBP-2 device - timed out");
		return(-EIO);
	}

	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_response, sizeof(struct sbp2_query_logins_response));

	SBP2_DEBUG("length_max_logins = %x",
		   (unsigned int)scsi_id->query_logins_response->length_max_logins);

	SBP2_INFO("Query logins to SBP-2 device successful");

	max_logins = RESPONSE_GET_MAX_LOGINS(scsi_id->query_logins_response->length_max_logins);
	SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
                                                                                
	active_logins = RESPONSE_GET_ACTIVE_LOGINS(scsi_id->query_logins_response->length_max_logins);
	SBP2_INFO("Number of active logins: %d", active_logins);
                                                                                
	if (active_logins >= max_logins) {
		return(-EIO);
	}
                                                                                
	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
1185
/*
Linus Torvalds's avatar
Linus Torvalds committed
1186 1187
 * This function is called in order to login to a particular SBP-2 device,
 * after a bus reset.
Linus Torvalds's avatar
Linus Torvalds committed
1188
 */
1189
static int sbp2_login_device(struct scsi_id_instance_data *scsi_id) 
Linus Torvalds's avatar
Linus Torvalds committed
1190
{
1191
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
1192 1193
	quadlet_t data[2];

Linus Torvalds's avatar
Linus Torvalds committed
1194
	SBP2_DEBUG("sbp2_login_device");
Linus Torvalds's avatar
Linus Torvalds committed
1195 1196

	if (!scsi_id->login_orb) {
Linus Torvalds's avatar
Linus Torvalds committed
1197
		SBP2_DEBUG("sbp2_login_device: login_orb not alloc'd!");
Linus Torvalds's avatar
Linus Torvalds committed
1198 1199 1200
		return(-EIO);
	}

1201 1202 1203 1204 1205 1206 1207
	if (!exclusive_login) {
		if (sbp2_query_logins(scsi_id)) {
			SBP2_ERR("Device does not support any more concurrent logins");
			return(-EIO);
		}
	}

Linus Torvalds's avatar
Linus Torvalds committed
1208 1209
	/* Set-up login ORB, assume no password */
	scsi_id->login_orb->password_hi = 0; 
Linus Torvalds's avatar
Linus Torvalds committed
1210
	scsi_id->login_orb->password_lo = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1211
	SBP2_DEBUG("sbp2_login_device: password_hi/lo initialized");
Linus Torvalds's avatar
Linus Torvalds committed
1212

Linus Torvalds's avatar
Linus Torvalds committed
1213 1214
	scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma;
	scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
Linus Torvalds's avatar
Linus Torvalds committed
1215
	SBP2_DEBUG("sbp2_login_device: login_response_hi/lo initialized");
Linus Torvalds's avatar
Linus Torvalds committed
1216

Linus Torvalds's avatar
Linus Torvalds committed
1217 1218
	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
1219
	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(exclusive_login);	/* Exclusive access to device */
Ben Collins's avatar
Ben Collins committed
1220 1221 1222 1223
	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);	/* Notify us of login complete */
	/* Set the lun if we were able to pull it from the device's unit directory */
	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
		scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
Ben Collins's avatar
Ben Collins committed
1224 1225
		SBP2_DEBUG("sbp2_query_logins: set lun to %d",
			   ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun));
Ben Collins's avatar
Ben Collins committed
1226
	}
Linus Torvalds's avatar
Linus Torvalds committed
1227
	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");
Linus Torvalds's avatar
Linus Torvalds committed
1228 1229 1230

	scsi_id->login_orb->passwd_resp_lengths =
		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
Linus Torvalds's avatar
Linus Torvalds committed
1231
	SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");
Linus Torvalds's avatar
Linus Torvalds committed
1232

Ben Collins's avatar
Ben Collins committed
1233
	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
1234
					     SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
Linus Torvalds's avatar
Linus Torvalds committed
1235 1236
	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
					      SBP2_STATUS_FIFO_ADDRESS_HI);
Linus Torvalds's avatar
Linus Torvalds committed
1237
	SBP2_DEBUG("sbp2_login_device: status FIFO initialized");
Linus Torvalds's avatar
Linus Torvalds committed
1238 1239 1240 1241 1242 1243

	/*
	 * Byte swap ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->login_orb, sizeof(struct sbp2_login_orb));

Linus Torvalds's avatar
Linus Torvalds committed
1244
	SBP2_DEBUG("sbp2_login_device: orb byte-swapped");
Linus Torvalds's avatar
Linus Torvalds committed
1245

Ben Collins's avatar
Ben Collins committed
1246 1247 1248
	sbp2util_packet_dump(scsi_id->login_orb, sizeof(struct sbp2_login_orb), 
			     "sbp2 login orb", scsi_id->login_orb_dma);

Linus Torvalds's avatar
Linus Torvalds committed
1249 1250 1251 1252 1253 1254
	/*
	 * Initialize login response and status fifo
	 */
	memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

Linus Torvalds's avatar
Linus Torvalds committed
1255
	SBP2_DEBUG("sbp2_login_device: login_response/status FIFO memset");
Linus Torvalds's avatar
Linus Torvalds committed
1256 1257 1258 1259 1260 1261 1262 1263

	/*
	 * Ok, let's write to the target's management agent register
	 */
	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->login_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

Ben Collins's avatar
Ben Collins committed
1264 1265
	atomic_set(&scsi_id->sbp2_login_complete, 0);

Ben Collins's avatar
Ben Collins committed
1266 1267
	SBP2_DEBUG("sbp2_login_device: prepared to write to %08x",
		   (unsigned int)scsi_id->sbp2_management_agent_addr);
Ben Collins's avatar
Ben Collins committed
1268
	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
Linus Torvalds's avatar
Linus Torvalds committed
1269
	SBP2_DEBUG("sbp2_login_device: written");
Linus Torvalds's avatar
Linus Torvalds committed
1270 1271

	/*
Ben Collins's avatar
Ben Collins committed
1272
	 * Wait for login status (up to 20 seconds)... 
Linus Torvalds's avatar
Linus Torvalds committed
1273
	 */
Ben Collins's avatar
Ben Collins committed
1274 1275 1276 1277
	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) {
		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
		return(-EIO);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1278 1279

	/*
Ben Collins's avatar
Ben Collins committed
1280
	 * Sanity. Make sure status returned matches login orb.
Linus Torvalds's avatar
Linus Torvalds committed
1281 1282
	 */
	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
Linus Torvalds's avatar
Linus Torvalds committed
1283
		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
Linus Torvalds's avatar
Linus Torvalds committed
1284 1285 1286 1287 1288
		return(-EIO);
	}

	/*
	 * Check status
Linus Torvalds's avatar
Linus Torvalds committed
1289
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1290 1291 1292 1293
	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {

Linus Torvalds's avatar
Linus Torvalds committed
1294
		SBP2_ERR("Error logging into SBP-2 device - login failed");
Linus Torvalds's avatar
Linus Torvalds committed
1295 1296 1297 1298
		return(-EIO);
	}

	/*
Linus Torvalds's avatar
Linus Torvalds committed
1299 1300
	 * Byte swap the login response, for use when reconnecting or
	 * logging out.
Linus Torvalds's avatar
Linus Torvalds committed
1301 1302 1303 1304
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->login_response, sizeof(struct sbp2_login_response));

	/*
Linus Torvalds's avatar
Linus Torvalds committed
1305
	 * Grab our command block agent address from the login response.
Linus Torvalds's avatar
Linus Torvalds committed
1306
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1307
	SBP2_DEBUG("command_block_agent_hi = %x",
Linus Torvalds's avatar
Linus Torvalds committed
1308
		   (unsigned int)scsi_id->login_response->command_block_agent_hi);
Linus Torvalds's avatar
Linus Torvalds committed
1309
	SBP2_DEBUG("command_block_agent_lo = %x",
Linus Torvalds's avatar
Linus Torvalds committed
1310
		   (unsigned int)scsi_id->login_response->command_block_agent_lo);
Linus Torvalds's avatar
Linus Torvalds committed
1311

Linus Torvalds's avatar
Linus Torvalds committed
1312 1313
	scsi_id->sbp2_command_block_agent_addr =
		((u64)scsi_id->login_response->command_block_agent_hi) << 32;
Linus Torvalds's avatar
Linus Torvalds committed
1314 1315 1316
	scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo);
	scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;

Linus Torvalds's avatar
Linus Torvalds committed
1317
	SBP2_INFO("Logged into SBP-2 device");
Linus Torvalds's avatar
Linus Torvalds committed
1318 1319 1320 1321 1322 1323

	return(0);

}

/*
Linus Torvalds's avatar
Linus Torvalds committed
1324 1325
 * This function is called in order to logout from a particular SBP-2
 * device, usually called during driver unload.
Linus Torvalds's avatar
Linus Torvalds committed
1326
 */
1327
static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id) 
Linus Torvalds's avatar
Linus Torvalds committed
1328
{
1329
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
1330 1331
	quadlet_t data[2];

Linus Torvalds's avatar
Linus Torvalds committed
1332
	SBP2_DEBUG("sbp2_logout_device");
Linus Torvalds's avatar
Linus Torvalds committed
1333 1334 1335 1336 1337 1338 1339 1340

	/*
	 * Set-up logout ORB
	 */
	scsi_id->logout_orb->reserved1 = 0x0;
	scsi_id->logout_orb->reserved2 = 0x0;
	scsi_id->logout_orb->reserved3 = 0x0;
	scsi_id->logout_orb->reserved4 = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
1341

Linus Torvalds's avatar
Linus Torvalds committed
1342 1343
	scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(LOGOUT_REQUEST);
	scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);
Linus Torvalds's avatar
Linus Torvalds committed
1344 1345 1346 1347

	/* Notify us when complete */
	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);

Linus Torvalds's avatar
Linus Torvalds committed
1348
	scsi_id->logout_orb->reserved5 = 0x0;
Ben Collins's avatar
Ben Collins committed
1349
	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
1350
					      SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
Linus Torvalds's avatar
Linus Torvalds committed
1351 1352
	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
					       SBP2_STATUS_FIFO_ADDRESS_HI);
Linus Torvalds's avatar
Linus Torvalds committed
1353 1354 1355 1356 1357 1358

	/*
	 * Byte swap ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb));

Ben Collins's avatar
Ben Collins committed
1359 1360 1361
	sbp2util_packet_dump(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb), 
			     "sbp2 logout orb", scsi_id->logout_orb_dma);

Linus Torvalds's avatar
Linus Torvalds committed
1362 1363 1364 1365 1366 1367 1368
	/*
	 * Ok, let's write to the target's management agent register
	 */
	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->logout_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

Ben Collins's avatar
Ben Collins committed
1369 1370
	atomic_set(&scsi_id->sbp2_login_complete, 0);

Ben Collins's avatar
Ben Collins committed
1371
	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
Linus Torvalds's avatar
Linus Torvalds committed
1372

Linus Torvalds's avatar
Linus Torvalds committed
1373
	/* Wait for device to logout...1 second. */
Ben Collins's avatar
Ben Collins committed
1374
	sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ);
Linus Torvalds's avatar
Linus Torvalds committed
1375

Linus Torvalds's avatar
Linus Torvalds committed
1376
	SBP2_INFO("Logged out of SBP-2 device");
Linus Torvalds's avatar
Linus Torvalds committed
1377 1378 1379 1380 1381 1382

	return(0);

}

/*
Linus Torvalds's avatar
Linus Torvalds committed
1383 1384
 * This function is called in order to reconnect to a particular SBP-2
 * device, after a bus reset.
Linus Torvalds's avatar
Linus Torvalds committed
1385
 */
1386
static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id) 
Linus Torvalds's avatar
Linus Torvalds committed
1387
{
1388
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
1389 1390
	quadlet_t data[2];

Linus Torvalds's avatar
Linus Torvalds committed
1391
	SBP2_DEBUG("sbp2_reconnect_device");
Linus Torvalds's avatar
Linus Torvalds committed
1392 1393 1394 1395 1396 1397 1398 1399

	/*
	 * Set-up reconnect ORB
	 */
	scsi_id->reconnect_orb->reserved1 = 0x0;
	scsi_id->reconnect_orb->reserved2 = 0x0;
	scsi_id->reconnect_orb->reserved3 = 0x0;
	scsi_id->reconnect_orb->reserved4 = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
1400

Linus Torvalds's avatar
Linus Torvalds committed
1401
	scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(RECONNECT_REQUEST);
Linus Torvalds's avatar
Linus Torvalds committed
1402 1403 1404 1405 1406 1407
	scsi_id->reconnect_orb->login_ID_misc |=
		ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);

	/* Notify us when complete */
	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);

Linus Torvalds's avatar
Linus Torvalds committed
1408
	scsi_id->reconnect_orb->reserved5 = 0x0;
Ben Collins's avatar
Ben Collins committed
1409
	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
1410
						 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
Linus Torvalds's avatar
Linus Torvalds committed
1411 1412 1413
	scsi_id->reconnect_orb->status_FIFO_hi =
		(ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);

Linus Torvalds's avatar
Linus Torvalds committed
1414 1415 1416 1417 1418
	/*
	 * Byte swap ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb));

Ben Collins's avatar
Ben Collins committed
1419 1420 1421
	sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb), 
			     "sbp2 reconnect orb", scsi_id->reconnect_orb_dma);

Linus Torvalds's avatar
Linus Torvalds committed
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
	/*
	 * Initialize status fifo
	 */
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	/*
	 * Ok, let's write to the target's management agent register
	 */
	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->reconnect_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

Ben Collins's avatar
Ben Collins committed
1434 1435
	atomic_set(&scsi_id->sbp2_login_complete, 0);

Ben Collins's avatar
Ben Collins committed
1436
	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
Linus Torvalds's avatar
Linus Torvalds committed
1437 1438

	/*
Ben Collins's avatar
Ben Collins committed
1439
	 * Wait for reconnect status (up to 1 second)...
Linus Torvalds's avatar
Linus Torvalds committed
1440
	 */
Ben Collins's avatar
Ben Collins committed
1441 1442 1443 1444
	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {
		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
		return(-EIO);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1445 1446

	/*
Ben Collins's avatar
Ben Collins committed
1447
	 * Sanity. Make sure status returned matches reconnect orb.
Linus Torvalds's avatar
Linus Torvalds committed
1448 1449
	 */
	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
Linus Torvalds's avatar
Linus Torvalds committed
1450
		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
Linus Torvalds's avatar
Linus Torvalds committed
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
		return(-EIO);
	}

	/*
	 * Check status
	 */
	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {

Linus Torvalds's avatar
Linus Torvalds committed
1461
		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed");
Linus Torvalds's avatar
Linus Torvalds committed
1462 1463 1464
		return(-EIO);
	}

Linus Torvalds's avatar
Linus Torvalds committed
1465
	SBP2_INFO("Reconnected to SBP-2 device");
Linus Torvalds's avatar
Linus Torvalds committed
1466 1467 1468 1469 1470 1471

	return(0);

}

/*
Linus Torvalds's avatar
Linus Torvalds committed
1472 1473
 * This function is called in order to set the busy timeout (number of
 * retries to attempt) on the sbp2 device. 
Linus Torvalds's avatar
Linus Torvalds committed
1474
 */
1475 1476
static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id)
{
Linus Torvalds's avatar
Linus Torvalds committed
1477 1478
	quadlet_t data;

Linus Torvalds's avatar
Linus Torvalds committed
1479
	SBP2_DEBUG("sbp2_set_busy_timeout");
Linus Torvalds's avatar
Linus Torvalds committed
1480 1481 1482 1483 1484 1485

	/*
	 * Ok, let's write to the target's busy timeout register
	 */
	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);

Ben Collins's avatar
Ben Collins committed
1486
	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
Linus Torvalds's avatar
Linus Torvalds committed
1487
		SBP2_ERR("sbp2_set_busy_timeout error");
Linus Torvalds's avatar
Linus Torvalds committed
1488 1489 1490 1491 1492
	}

	return(0);
}

1493

Linus Torvalds's avatar
Linus Torvalds committed
1494
/*
Linus Torvalds's avatar
Linus Torvalds committed
1495 1496 1497
 * This function is called to parse sbp2 device's config rom unit
 * directory. Used to determine things like sbp2 management agent offset,
 * and command set used (SCSI or RBC). 
Linus Torvalds's avatar
Linus Torvalds committed
1498
 */
1499 1500
static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
				      struct unit_directory *ud)
Linus Torvalds's avatar
Linus Torvalds committed
1501
{
1502 1503
	struct csr1212_keyval *kv;
	struct csr1212_dentry *dentry;
Ben Collins's avatar
Ben Collins committed
1504 1505 1506
	u64 management_agent_addr;
	u32 command_set_spec_id, command_set, unit_characteristics,
		firmware_revision, workarounds;
Linus Torvalds's avatar
Linus Torvalds committed
1507
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
1508

Linus Torvalds's avatar
Linus Torvalds committed
1509
	SBP2_DEBUG("sbp2_parse_unit_directory");
Linus Torvalds's avatar
Linus Torvalds committed
1510

Ben Collins's avatar
Ben Collins committed
1511 1512 1513 1514 1515
	management_agent_addr = 0x0;
	command_set_spec_id = 0x0;
	command_set = 0x0;
	unit_characteristics = 0x0;
	firmware_revision = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
1516

Linus Torvalds's avatar
Linus Torvalds committed
1517
	/* Handle different fields in the unit directory, based on keys */
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
	csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
		switch (kv->key.id) {
		case CSR1212_KV_ID_DEPENDENT_INFO:
			if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET) {
				/* Save off the management agent address */
				management_agent_addr =
					CSR1212_REGISTER_SPACE_BASE +
					(kv->value.csr_offset << 2);

				SBP2_DEBUG("sbp2_management_agent_addr = %x",
					   (unsigned int) management_agent_addr);
1529
			} else
1530
				scsi_id->sbp2_device_type_and_lun = kv->value.immediate;
Linus Torvalds's avatar
Linus Torvalds committed
1531
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1532

Linus Torvalds's avatar
Linus Torvalds committed
1533 1534
		case SBP2_COMMAND_SET_SPEC_ID_KEY:
			/* Command spec organization */
1535
			command_set_spec_id = kv->value.immediate;
Linus Torvalds's avatar
Linus Torvalds committed
1536
			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
Ben Collins's avatar
Ben Collins committed
1537
				   (unsigned int) command_set_spec_id);
Linus Torvalds's avatar
Linus Torvalds committed
1538
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1539

Linus Torvalds's avatar
Linus Torvalds committed
1540 1541
		case SBP2_COMMAND_SET_KEY:
			/* Command set used by sbp2 device */
1542
			command_set = kv->value.immediate;
Linus Torvalds's avatar
Linus Torvalds committed
1543
			SBP2_DEBUG("sbp2_command_set = %x",
Ben Collins's avatar
Ben Collins committed
1544
				   (unsigned int) command_set);
Linus Torvalds's avatar
Linus Torvalds committed
1545
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1546

Linus Torvalds's avatar
Linus Torvalds committed
1547 1548 1549 1550 1551
		case SBP2_UNIT_CHARACTERISTICS_KEY:
			/*
			 * Unit characterisitcs (orb related stuff
			 * that I'm not yet paying attention to)
			 */
1552
			unit_characteristics = kv->value.immediate;
Linus Torvalds's avatar
Linus Torvalds committed
1553
			SBP2_DEBUG("sbp2_unit_characteristics = %x",
Ben Collins's avatar
Ben Collins committed
1554
				   (unsigned int) unit_characteristics);
Linus Torvalds's avatar
Linus Torvalds committed
1555
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1556

Linus Torvalds's avatar
Linus Torvalds committed
1557
		case SBP2_FIRMWARE_REVISION_KEY:
Ben Collins's avatar
Ben Collins committed
1558
			/* Firmware revision */
1559
			firmware_revision = kv->value.immediate;
1560
			if (force_inquiry_hack)
1561
				SBP2_INFO("sbp2_firmware_revision = %x",
Ben Collins's avatar
Ben Collins committed
1562
				   (unsigned int) firmware_revision);
1563
			else	SBP2_DEBUG("sbp2_firmware_revision = %x",
Ben Collins's avatar
Ben Collins committed
1564
				   (unsigned int) firmware_revision);
Linus Torvalds's avatar
Linus Torvalds committed
1565
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1566

Linus Torvalds's avatar
Linus Torvalds committed
1567 1568
		default:
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1569 1570
		}
	}
Ben Collins's avatar
Ben Collins committed
1571 1572 1573

	/* This is the start of our broken device checking. We try to hack
	 * around oddities and known defects.  */
Ben Collins's avatar
Ben Collins committed
1574
	workarounds = 0x0;
Ben Collins's avatar
Ben Collins committed
1575 1576 1577

	/* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a
	 * bridge with 128KB max transfer size limitation. For sanity, we
1578
	 * only voice this when the current max_sectors setting
Ben Collins's avatar
Ben Collins committed
1579 1580 1581 1582
	 * exceeds the 128k limit. By default, that is not the case.
	 *
	 * It would be really nice if we could detect this before the scsi
	 * host gets initialized. That way we can down-force the
1583
	 * max_sectors to account for it. That is not currently
Ben Collins's avatar
Ben Collins committed
1584
	 * possible.  */
Ben Collins's avatar
Ben Collins committed
1585
	if ((firmware_revision & 0xffff00) ==
Ben Collins's avatar
Ben Collins committed
1586
			SBP2_128KB_BROKEN_FIRMWARE &&
1587
			(max_sectors * 512) > (128*1024)) {
Ben Collins's avatar
Ben Collins committed
1588
		SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.",
1589
				NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));
1590 1591
		SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!",
				max_sectors);
Ben Collins's avatar
Ben Collins committed
1592
		workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;
Ben Collins's avatar
Ben Collins committed
1593 1594 1595 1596
	}

	/* Check for a blacklisted set of devices that require us to force
	 * a 36 byte host inquiry. This can be overriden as a module param
1597 1598
	 * (to force all hosts).  */
	for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) {
Ben Collins's avatar
Ben Collins committed
1599
		if ((firmware_revision & 0xffff00) ==
Ben Collins's avatar
Ben Collins committed
1600 1601
				sbp2_broken_inquiry_list[i]) {
			SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround",
1602
					NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));
Ben Collins's avatar
Ben Collins committed
1603
			workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;
1604
			break; /* No need to continue. */
Ben Collins's avatar
Ben Collins committed
1605 1606
		}
	}
Ben Collins's avatar
Ben Collins committed
1607

1608
	/* If this is a logical unit directory entry, process the parent
1609
	 * to get the values. */
1610 1611 1612
	if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
		struct unit_directory *parent_ud =
			container_of(ud->device.parent, struct unit_directory, device);
1613
		sbp2_parse_unit_directory(scsi_id, parent_ud);
1614
	} else {
1615 1616 1617 1618 1619 1620
		scsi_id->sbp2_management_agent_addr = management_agent_addr;
		scsi_id->sbp2_command_set_spec_id = command_set_spec_id;
		scsi_id->sbp2_command_set = command_set;
		scsi_id->sbp2_unit_characteristics = unit_characteristics;
		scsi_id->sbp2_firmware_revision = firmware_revision;
		scsi_id->workarounds = workarounds;
Ben Collins's avatar
Ben Collins committed
1621
	}
Linus Torvalds's avatar
Linus Torvalds committed
1622 1623 1624
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
1625
 * This function is called in order to determine the max speed and packet
Linus Torvalds's avatar
Linus Torvalds committed
1626 1627 1628 1629 1630 1631
 * size we can use in our ORBs. Note, that we (the driver and host) only
 * initiate the transaction. The SBP-2 device actually transfers the data
 * (by reading from the DMA area we tell it). This means that the SBP-2
 * device decides the actual maximum data it can transfer. We just tell it
 * the speed that it needs to use, and the max_rec the host supports, and
 * it takes care of the rest.
Linus Torvalds's avatar
Linus Torvalds committed
1632
 */
1633
static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
Linus Torvalds's avatar
Linus Torvalds committed
1634
{
1635 1636
	struct sbp2scsi_host_info *hi = scsi_id->hi;

Linus Torvalds's avatar
Linus Torvalds committed
1637 1638 1639
	SBP2_DEBUG("sbp2_max_speed_and_size");

	/* Initial setting comes from the hosts speed map */
Ben Collins's avatar
Ben Collins committed
1640 1641
	scsi_id->speed_code = hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64
						  + NODEID_TO_NODE(scsi_id->ne->nodeid)];
Linus Torvalds's avatar
Linus Torvalds committed
1642 1643

	/* Bump down our speed if the user requested it */
1644 1645
	if (scsi_id->speed_code > max_speed) {
		scsi_id->speed_code = max_speed;
Linus Torvalds's avatar
Linus Torvalds committed
1646 1647
		SBP2_ERR("Forcing SBP-2 max speed down to %s",
			 hpsb_speedto_str[scsi_id->speed_code]);
Linus Torvalds's avatar
Linus Torvalds committed
1648 1649
	}

Linus Torvalds's avatar
Linus Torvalds committed
1650 1651
	/* Payload size is the lesser of what our speed supports and what
	 * our host supports.  */
Ben Collins's avatar
Ben Collins committed
1652
	scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code],
1653
					(u8)(hi->host->csr.max_rec - 1));
Linus Torvalds's avatar
Linus Torvalds committed
1654

1655 1656 1657
	SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
		 NODE_BUS_ARGS(hi->host, scsi_id->ne->nodeid),
		 hpsb_speedto_str[scsi_id->speed_code],
Linus Torvalds's avatar
Linus Torvalds committed
1658
		 1 << ((u32)scsi_id->max_payload_size + 2));
Linus Torvalds's avatar
Linus Torvalds committed
1659

Linus Torvalds's avatar
Linus Torvalds committed
1660 1661 1662 1663 1664 1665
	return(0);
}

/*
 * This function is called in order to perform a SBP-2 agent reset. 
 */
1666
static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait) 
Linus Torvalds's avatar
Linus Torvalds committed
1667
{
1668
	quadlet_t data;
Ben Collins's avatar
Ben Collins committed
1669 1670 1671
	u64 addr;
	int retval;

Linus Torvalds's avatar
Linus Torvalds committed
1672
	SBP2_DEBUG("sbp2_agent_reset");
Linus Torvalds's avatar
Linus Torvalds committed
1673 1674 1675 1676

	/*
	 * Ok, let's write to the target's management agent register
	 */
1677
	data = ntohl(SBP2_AGENT_RESET_DATA);
Ben Collins's avatar
Ben Collins committed
1678
	addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
Linus Torvalds's avatar
Linus Torvalds committed
1679

Ben Collins's avatar
Ben Collins committed
1680 1681 1682 1683
	if (wait)
		retval = hpsb_node_write(scsi_id->ne, addr, &data, 4);
	else
		retval = sbp2util_node_write_no_wait(scsi_id->ne, addr, &data, 4);
Linus Torvalds's avatar
Linus Torvalds committed
1684

Ben Collins's avatar
Ben Collins committed
1685 1686 1687
	if (retval < 0) {
		SBP2_ERR("hpsb_node_write failed.\n");
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698
	}

	/*
	 * Need to make sure orb pointer is written on next command
	 */
	scsi_id->last_orb = NULL;

	return(0);
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
1699 1700
 * This function is called to create the actual command orb and s/g list
 * out of the scsi command itself.
Linus Torvalds's avatar
Linus Torvalds committed
1701
 */
1702
static int sbp2_create_command_orb(struct scsi_id_instance_data *scsi_id,
Linus Torvalds's avatar
Linus Torvalds committed
1703 1704 1705 1706
				   struct sbp2_command_info *command,
				   unchar *scsi_cmd,
				   unsigned int scsi_use_sg,
				   unsigned int scsi_request_bufflen,
Linus Torvalds's avatar
Linus Torvalds committed
1707 1708
				   void *scsi_request_buffer, 
				   unsigned char scsi_dir)
Linus Torvalds's avatar
Linus Torvalds committed
1709
{
1710
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
1711 1712 1713 1714
	struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
	struct sbp2_command_orb *command_orb = &command->command_orb;
	struct sbp2_unrestricted_page_table *scatter_gather_element =
		&command->scatter_gather_element[0];
Linus Torvalds's avatar
Linus Torvalds committed
1715 1716
	int dma_dir = scsi_to_pci_dma_dir (scsi_dir);
	u32 sg_count, sg_len, orb_direction;
Linus Torvalds's avatar
Linus Torvalds committed
1717 1718 1719 1720 1721 1722
	dma_addr_t sg_addr;
	int i;

	/*
	 * Set-up our command ORB..
	 *
Linus Torvalds's avatar
Linus Torvalds committed
1723 1724 1725 1726
	 * NOTE: We're doing unrestricted page tables (s/g), as this is
	 * best performance (at least with the devices I have). This means
	 * that data_size becomes the number of s/g elements, and
	 * page_size should be zero (for unrestricted).
Linus Torvalds's avatar
Linus Torvalds committed
1727
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1728 1729
	command_orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
	command_orb->next_ORB_lo = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
1730 1731 1732 1733
	command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size);
	command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code);
	command_orb->misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */

Linus Torvalds's avatar
Linus Torvalds committed
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
	/*
	 * Get the direction of the transfer. If the direction is unknown, then use our
	 * goofy table as a back-up.
	 */
	switch (scsi_dir) {
		case SCSI_DATA_NONE:
			orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
			break;
		case SCSI_DATA_WRITE:
			orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
			break;
		case SCSI_DATA_READ:
			orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
			break;
		case SCSI_DATA_UNKNOWN:
		default:
			SBP2_ERR("SCSI data transfer direction not specified. "
				 "Update the SBP2 direction table in sbp2.h if " 
				 "necessary for your application");
			print_command (scsi_cmd);
			orb_direction = sbp2scsi_direction_table[*scsi_cmd];
			break;
	}

Linus Torvalds's avatar
Linus Torvalds committed
1758
	/*
Linus Torvalds's avatar
Linus Torvalds committed
1759 1760
	 * Set-up our pagetable stuff... unfortunately, this has become
	 * messier than I'd like. Need to clean this up a bit.   ;-)
Linus Torvalds's avatar
Linus Torvalds committed
1761
	 */
Linus Torvalds's avatar
Linus Torvalds committed
1762
	if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
Linus Torvalds's avatar
Linus Torvalds committed
1763

Linus Torvalds's avatar
Linus Torvalds committed
1764
		SBP2_DEBUG("No data transfer");
Linus Torvalds's avatar
Linus Torvalds committed
1765 1766 1767 1768

		/*
		 * Handle no data transfer
		 */
Linus Torvalds's avatar
Linus Torvalds committed
1769 1770
		command_orb->data_descriptor_hi = 0x0;
		command_orb->data_descriptor_lo = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
1771 1772 1773 1774
		command_orb->misc |= ORB_SET_DIRECTION(1);

	} else if (scsi_use_sg) {

Linus Torvalds's avatar
Linus Torvalds committed
1775
		SBP2_DEBUG("Use scatter/gather");
Linus Torvalds's avatar
Linus Torvalds committed
1776 1777 1778 1779 1780 1781

		/*
		 * Special case if only one element (and less than 64KB in size)
		 */
		if ((scsi_use_sg == 1) && (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) {

Linus Torvalds's avatar
Linus Torvalds committed
1782
			SBP2_DEBUG("Only one s/g element");
Linus Torvalds's avatar
Linus Torvalds committed
1783 1784
			command->dma_dir = dma_dir;
			command->dma_size = sgpnt[0].length;
Linus Torvalds's avatar
Linus Torvalds committed
1785 1786 1787 1788 1789 1790 1791
			command->dma_type = CMD_DMA_PAGE;
			command->cmd_dma = pci_map_page(hi->host->pdev,
							sgpnt[0].page,
							sgpnt[0].offset,
							command->dma_size,
							command->dma_dir);
			SBP2_DMA_ALLOC("single page scatter element");
Linus Torvalds's avatar
Linus Torvalds committed
1792 1793 1794 1795

			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->cmd_dma;
			command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size);
Linus Torvalds's avatar
Linus Torvalds committed
1796
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
Linus Torvalds's avatar
Linus Torvalds committed
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807

		} else {
			int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir);
			SBP2_DMA_ALLOC("scatter list");

			command->dma_size = scsi_use_sg;
			command->dma_dir = dma_dir;
			command->sge_buffer = sgpnt;

			/* use page tables (s/g) */
			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
Linus Torvalds's avatar
Linus Torvalds committed
1808
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
Linus Torvalds's avatar
Linus Torvalds committed
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->sge_dma;

			/*
			 * Loop through and fill out our sbp-2 page tables
			 * (and split up anything too large)
			 */
			for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) {
				sg_len = sg_dma_len(sgpnt);
				sg_addr = sg_dma_address(sgpnt);
				while (sg_len) {
					scatter_gather_element[sg_count].segment_base_lo = sg_addr;
					if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
						scatter_gather_element[sg_count].length_segment_base_hi =  
							PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
						sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
						sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
					} else {
						scatter_gather_element[sg_count].length_segment_base_hi = 
							PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
						sg_len = 0;
					}
					sg_count++;
				}
			}

Linus Torvalds's avatar
Linus Torvalds committed
1835 1836
			/* Number of page table (s/g) elements */
			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);
Linus Torvalds's avatar
Linus Torvalds committed
1837

Ben Collins's avatar
Ben Collins committed
1838 1839 1840 1841
			sbp2util_packet_dump(scatter_gather_element, 
					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count, 
					     "sbp2 s/g list", command->sge_dma);

Linus Torvalds's avatar
Linus Torvalds committed
1842 1843 1844 1845
			/*
			 * Byte swap page tables if necessary
			 */
			sbp2util_cpu_to_be32_buffer(scatter_gather_element, 
Linus Torvalds's avatar
Linus Torvalds committed
1846 1847
						    (sizeof(struct sbp2_unrestricted_page_table)) *
						    sg_count);
Linus Torvalds's avatar
Linus Torvalds committed
1848 1849 1850 1851 1852

		}

	} else {

Linus Torvalds's avatar
Linus Torvalds committed
1853
		SBP2_DEBUG("No scatter/gather");
Linus Torvalds's avatar
Linus Torvalds committed
1854 1855 1856

		command->dma_dir = dma_dir;
		command->dma_size = scsi_request_bufflen;
Linus Torvalds's avatar
Linus Torvalds committed
1857
		command->dma_type = CMD_DMA_SINGLE;
Linus Torvalds's avatar
Linus Torvalds committed
1858 1859 1860 1861 1862 1863
		command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer,
						   command->dma_size,
						   command->dma_dir);
		SBP2_DMA_ALLOC("single bulk");

		/*
Linus Torvalds's avatar
Linus Torvalds committed
1864 1865
		 * Handle case where we get a command w/o s/g enabled (but
		 * check for transfers larger than 64K)
Linus Torvalds's avatar
Linus Torvalds committed
1866 1867 1868 1869 1870 1871
		 */
		if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) {

			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->cmd_dma;
			command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
Linus Torvalds's avatar
Linus Torvalds committed
1872
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
Linus Torvalds's avatar
Linus Torvalds committed
1873 1874

			/*
Linus Torvalds's avatar
Linus Torvalds committed
1875 1876
			 * Sanity, in case our direction table is not
			 * up-to-date
Linus Torvalds's avatar
Linus Torvalds committed
1877 1878
			 */
			if (!scsi_request_bufflen) {
Linus Torvalds's avatar
Linus Torvalds committed
1879 1880
				command_orb->data_descriptor_hi = 0x0;
				command_orb->data_descriptor_lo = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
1881 1882 1883 1884 1885
				command_orb->misc |= ORB_SET_DIRECTION(1);
			}

		} else {
			/*
Linus Torvalds's avatar
Linus Torvalds committed
1886 1887
			 * Need to turn this into page tables, since the
			 * buffer is too large.
Linus Torvalds's avatar
Linus Torvalds committed
1888 1889 1890
			 */                     
			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->sge_dma;
Linus Torvalds's avatar
Linus Torvalds committed
1891 1892 1893

			/* Use page tables (s/g) */
			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
Linus Torvalds's avatar
Linus Torvalds committed
1894
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
Linus Torvalds's avatar
Linus Torvalds committed
1895 1896

			/*
Linus Torvalds's avatar
Linus Torvalds committed
1897 1898
			 * fill out our sbp-2 page tables (and split up
			 * the large buffer)
Linus Torvalds's avatar
Linus Torvalds committed
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917
			 */
			sg_count = 0;
			sg_len = scsi_request_bufflen;
			sg_addr = command->cmd_dma;
			while (sg_len) {
				scatter_gather_element[sg_count].segment_base_lo = sg_addr;
				if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
					scatter_gather_element[sg_count].length_segment_base_hi = 
						PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
					sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
					sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
				} else {
					scatter_gather_element[sg_count].length_segment_base_hi = 
						PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
					sg_len = 0;
				}
				sg_count++;
			}

Linus Torvalds's avatar
Linus Torvalds committed
1918 1919
			/* Number of page table (s/g) elements */
			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);
Linus Torvalds's avatar
Linus Torvalds committed
1920

Ben Collins's avatar
Ben Collins committed
1921 1922 1923 1924
			sbp2util_packet_dump(scatter_gather_element, 
					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count, 
					     "sbp2 s/g list", command->sge_dma);

Linus Torvalds's avatar
Linus Torvalds committed
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
			/*
			 * Byte swap page tables if necessary
			 */
			sbp2util_cpu_to_be32_buffer(scatter_gather_element, 
						    (sizeof(struct sbp2_unrestricted_page_table)) *
						     sg_count);

		}

	}

	/*
	 * Byte swap command ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(command_orb, sizeof(struct sbp2_command_orb));

	/*
	 * Put our scsi command in the command ORB
	 */
	memset(command_orb->cdb, 0, 12);
	memcpy(command_orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd));

	return(0);
}
 
/*
 * This function is called in order to begin a regular SBP-2 command. 
 */
1953
static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
Linus Torvalds's avatar
Linus Torvalds committed
1954 1955
				 struct sbp2_command_info *command)
{
1956
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
1957
	struct sbp2_command_orb *command_orb = &command->command_orb;
Ben Collins's avatar
Ben Collins committed
1958 1959
	struct node_entry *ne = scsi_id->ne;
	u64 addr;
Linus Torvalds's avatar
Linus Torvalds committed
1960 1961

	outstanding_orb_incr;
Ben Collins's avatar
Ben Collins committed
1962 1963
	SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
			command_orb, global_outstanding_command_orbs);
Linus Torvalds's avatar
Linus Torvalds committed
1964

Linus Torvalds's avatar
Linus Torvalds committed
1965 1966 1967 1968 1969 1970
	pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
			    sizeof(struct sbp2_command_orb),
			    PCI_DMA_BIDIRECTIONAL);
	pci_dma_sync_single(hi->host->pdev, command->sge_dma,
			    sizeof(command->scatter_gather_element),
			    PCI_DMA_BIDIRECTIONAL);
Linus Torvalds's avatar
Linus Torvalds committed
1971 1972 1973 1974
	/*
	 * Check to see if there are any previous orbs to use
	 */
	if (scsi_id->last_orb == NULL) {
Ben Collins's avatar
Ben Collins committed
1975 1976
		quadlet_t data[2];

Linus Torvalds's avatar
Linus Torvalds committed
1977 1978 1979
		/*
		 * Ok, let's write to the target's management agent register
		 */
Ben Collins's avatar
Ben Collins committed
1980 1981 1982 1983
		addr = scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET;
		data[0] = ORB_SET_NODE_ID(hi->host->node_id);
		data[1] = command->command_orb_dma;
		sbp2util_cpu_to_be32_buffer(data, 8);
Linus Torvalds's avatar
Linus Torvalds committed
1984

Ben Collins's avatar
Ben Collins committed
1985
		SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);
Linus Torvalds's avatar
Linus Torvalds committed
1986

Ben Collins's avatar
Ben Collins committed
1987 1988 1989
		if (sbp2util_node_write_no_wait(ne, addr, data, 8) < 0) {
			SBP2_ERR("sbp2util_node_write_no_wait failed.\n");
			return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
1990 1991
		}

Ben Collins's avatar
Ben Collins committed
1992 1993
		SBP2_ORB_DEBUG("write command agent complete");

Linus Torvalds's avatar
Linus Torvalds committed
1994
		scsi_id->last_orb = command_orb;
Linus Torvalds's avatar
Linus Torvalds committed
1995
		scsi_id->last_orb_dma = command->command_orb_dma;
Linus Torvalds's avatar
Linus Torvalds committed
1996 1997

	} else {
Ben Collins's avatar
Ben Collins committed
1998
		quadlet_t data;
Linus Torvalds's avatar
Linus Torvalds committed
1999 2000 2001 2002 2003 2004 2005 2006

		/*
		 * We have an orb already sent (maybe or maybe not
		 * processed) that we can append this orb to. So do so,
		 * and ring the doorbell. Have to be very careful
		 * modifying these next orb pointers, as they are accessed
		 * both by the sbp2 device and us.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
2007 2008 2009 2010
		scsi_id->last_orb->next_ORB_lo =
			cpu_to_be32(command->command_orb_dma);
		/* Tells hardware that this pointer is valid */
		scsi_id->last_orb->next_ORB_hi = 0x0;
Linus Torvalds's avatar
Linus Torvalds committed
2011 2012 2013
		pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma,
				    sizeof(struct sbp2_command_orb),
				    PCI_DMA_BIDIRECTIONAL);
Linus Torvalds's avatar
Linus Torvalds committed
2014

Linus Torvalds's avatar
Linus Torvalds committed
2015
		/*
Ben Collins's avatar
Ben Collins committed
2016
		 * Ring the doorbell
Linus Torvalds's avatar
Linus Torvalds committed
2017
		 */
Ben Collins's avatar
Ben Collins committed
2018 2019
		data = cpu_to_be32(command->command_orb_dma);
		addr = scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET;
Linus Torvalds's avatar
Linus Torvalds committed
2020

Ben Collins's avatar
Ben Collins committed
2021
		SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);
Linus Torvalds's avatar
Linus Torvalds committed
2022

Ben Collins's avatar
Ben Collins committed
2023 2024 2025
		if (sbp2util_node_write_no_wait(ne, addr, &data, 4) < 0) {
			SBP2_ERR("sbp2util_node_write_no_wait failed");
			return(-EIO);
Linus Torvalds's avatar
Linus Torvalds committed
2026 2027 2028
		}

		scsi_id->last_orb = command_orb;
Linus Torvalds's avatar
Linus Torvalds committed
2029
		scsi_id->last_orb_dma = command->command_orb_dma;
Linus Torvalds's avatar
Linus Torvalds committed
2030 2031 2032 2033 2034 2035 2036 2037

	}
       	return(0);
}

/*
 * This function is called in order to begin a regular SBP-2 command. 
 */
2038
static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
Linus Torvalds's avatar
Linus Torvalds committed
2039 2040 2041
			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
	unchar *cmd = (unchar *) SCpnt->cmnd;
Linus Torvalds's avatar
Linus Torvalds committed
2042
	unsigned int request_bufflen = SCpnt->request_bufflen;
Linus Torvalds's avatar
Linus Torvalds committed
2043 2044
	struct sbp2_command_info *command;

Linus Torvalds's avatar
Linus Torvalds committed
2045
	SBP2_DEBUG("sbp2_send_command");
Ben Collins's avatar
Ben Collins committed
2046 2047
#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)
	printk("[scsi command]\n   ");
Linus Torvalds's avatar
Linus Torvalds committed
2048 2049 2050
	print_command (cmd);
#endif
	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
Linus Torvalds's avatar
Linus Torvalds committed
2051
	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
Linus Torvalds's avatar
Linus Torvalds committed
2052 2053 2054 2055

	/*
	 * Allocate a command orb and s/g structure
	 */
2056
	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done);
Linus Torvalds's avatar
Linus Torvalds committed
2057 2058 2059 2060
	if (!command) {
		return(-EIO);
	}

Linus Torvalds's avatar
Linus Torvalds committed
2061 2062 2063
	/*
	 * The scsi stack sends down a request_bufflen which does not match the
	 * length field in the scsi cdb. This causes some sbp2 devices to 
Ben Collins's avatar
Ben Collins committed
2064
	 * reject this inquiry command. Fix the request_bufflen. 
Linus Torvalds's avatar
Linus Torvalds committed
2065 2066
	 */
	if (*cmd == INQUIRY) {
2067
		if (force_inquiry_hack || scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK)
Ben Collins's avatar
Ben Collins committed
2068 2069 2070
			request_bufflen = cmd[4] = 0x24;
		else
			request_bufflen = cmd[4];
Linus Torvalds's avatar
Linus Torvalds committed
2071 2072
	}

Linus Torvalds's avatar
Linus Torvalds committed
2073 2074 2075
	/*
	 * Now actually fill in the comamnd orb and sbp2 s/g list
	 */
2076
	sbp2_create_command_orb(scsi_id, command, cmd, SCpnt->use_sg,
Linus Torvalds's avatar
Linus Torvalds committed
2077 2078
				request_bufflen, SCpnt->request_buffer,
				SCpnt->sc_data_direction); 
Linus Torvalds's avatar
Linus Torvalds committed
2079
	/*
Linus Torvalds's avatar
Linus Torvalds committed
2080
	 * Update our cdb if necessary (to handle sbp2 RBC command set
Linus Torvalds's avatar
Linus Torvalds committed
2081
	 * differences). This is where the command set hacks go!   =)
Linus Torvalds's avatar
Linus Torvalds committed
2082
	 */
Ben Collins's avatar
Ben Collins committed
2083 2084 2085 2086
	sbp2_check_sbp2_command(scsi_id, command->command_orb.cdb);

	sbp2util_packet_dump(&command->command_orb, sizeof(struct sbp2_command_orb), 
			     "sbp2 command orb", command->command_orb_dma);
Linus Torvalds's avatar
Linus Torvalds committed
2087 2088 2089 2090 2091 2092 2093 2094 2095

	/*
	 * Initialize status fifo
	 */
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	/*
	 * Link up the orb, and ring the doorbell if needed
	 */
2096
	sbp2_link_orb_command(scsi_id, command);
Linus Torvalds's avatar
Linus Torvalds committed
2097 2098 2099 2100 2101 2102
	
	return(0);
}


/*
Linus Torvalds's avatar
Linus Torvalds committed
2103 2104
 * This function deals with command set differences between Linux scsi
 * command set and sbp2 RBC command set.
Linus Torvalds's avatar
Linus Torvalds committed
2105
 */
Ben Collins's avatar
Ben Collins committed
2106
static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd)
Linus Torvalds's avatar
Linus Torvalds committed
2107 2108
{
	unchar new_cmd[16];
Ben Collins's avatar
Ben Collins committed
2109
	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
Linus Torvalds's avatar
Linus Torvalds committed
2110

Linus Torvalds's avatar
Linus Torvalds committed
2111
	SBP2_DEBUG("sbp2_check_sbp2_command");
Linus Torvalds's avatar
Linus Torvalds committed
2112 2113 2114 2115 2116

	switch (*cmd) {
		
		case READ_6:

Ben Collins's avatar
Ben Collins committed
2117
			if (sbp2_command_conversion_device_type(device_type)) {
Linus Torvalds's avatar
Linus Torvalds committed
2118

Ben Collins's avatar
Ben Collins committed
2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
				SBP2_DEBUG("Convert READ_6 to READ_10");
					    
				/*
				 * Need to turn read_6 into read_10
				 */
				new_cmd[0] = 0x28;
				new_cmd[1] = (cmd[1] & 0xe0);
				new_cmd[2] = 0x0;
				new_cmd[3] = (cmd[1] & 0x1f);
				new_cmd[4] = cmd[2];
				new_cmd[5] = cmd[3];
				new_cmd[6] = 0x0;
				new_cmd[7] = 0x0;
				new_cmd[8] = cmd[4];
				new_cmd[9] = cmd[5];
	
				memcpy(cmd, new_cmd, 10);

			}
Linus Torvalds's avatar
Linus Torvalds committed
2138 2139 2140 2141 2142

			break;

		case WRITE_6:

Ben Collins's avatar
Ben Collins committed
2143
			if (sbp2_command_conversion_device_type(device_type)) {
Linus Torvalds's avatar
Linus Torvalds committed
2144

Ben Collins's avatar
Ben Collins committed
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
				SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
	
				/*
				 * Need to turn write_6 into write_10
				 */
				new_cmd[0] = 0x2a;
				new_cmd[1] = (cmd[1] & 0xe0);
				new_cmd[2] = 0x0;
				new_cmd[3] = (cmd[1] & 0x1f);
				new_cmd[4] = cmd[2];
				new_cmd[5] = cmd[3];
				new_cmd[6] = 0x0;
				new_cmd[7] = 0x0;
				new_cmd[8] = cmd[4];
				new_cmd[9] = cmd[5];
	
				memcpy(cmd, new_cmd, 10);

			}
Linus Torvalds's avatar
Linus Torvalds committed
2164 2165 2166 2167 2168

			break;

		case MODE_SENSE:

Ben Collins's avatar
Ben Collins committed
2169
			if (sbp2_command_conversion_device_type(device_type)) {
Linus Torvalds's avatar
Linus Torvalds committed
2170

Ben Collins's avatar
Ben Collins committed
2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189
				SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10");

				/*
				 * Need to turn mode_sense_6 into mode_sense_10
				 */
				new_cmd[0] = 0x5a;
				new_cmd[1] = cmd[1];
				new_cmd[2] = cmd[2];
				new_cmd[3] = 0x0;
				new_cmd[4] = 0x0;
				new_cmd[5] = 0x0;
				new_cmd[6] = 0x0;
				new_cmd[7] = 0x0;
				new_cmd[8] = cmd[4];
				new_cmd[9] = cmd[5];
	
				memcpy(cmd, new_cmd, 10);

			}
Linus Torvalds's avatar
Linus Torvalds committed
2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210

			break;

		case MODE_SELECT:

			/*
			 * TODO. Probably need to change mode select to 10 byte version
			 */

		default:
			break;
	}

	return;
}

/*
 * Translates SBP-2 status into SCSI sense data for check conditions
 */
static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data)
{
Linus Torvalds's avatar
Linus Torvalds committed
2211
	SBP2_DEBUG("sbp2_status_to_sense_data");
Linus Torvalds's avatar
Linus Torvalds committed
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239

	/*
	 * Ok, it's pretty ugly...   ;-)
	 */
	sense_data[0] = 0x70;
	sense_data[1] = 0x0;
	sense_data[2] = sbp2_status[9];
	sense_data[3] = sbp2_status[12];
	sense_data[4] = sbp2_status[13];
	sense_data[5] = sbp2_status[14];
	sense_data[6] = sbp2_status[15];
	sense_data[7] = 10;
	sense_data[8] = sbp2_status[16];
	sense_data[9] = sbp2_status[17];
	sense_data[10] = sbp2_status[18];
	sense_data[11] = sbp2_status[19];
	sense_data[12] = sbp2_status[10];
	sense_data[13] = sbp2_status[11];
	sense_data[14] = sbp2_status[20];
	sense_data[15] = sbp2_status[21];

	return(sbp2_status[8] & 0x3f);	/* return scsi status */
}

/*
 * This function is called after a command is completed, in order to do any necessary SBP-2
 * response data translations for the SCSI stack
 */
Ben Collins's avatar
Ben Collins committed
2240
static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, 
Linus Torvalds's avatar
Linus Torvalds committed
2241 2242 2243
				     Scsi_Cmnd *SCpnt)
{
	u8 *scsi_buf = SCpnt->request_buffer;
Linus Torvalds's avatar
Linus Torvalds committed
2244 2245
	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);

Linus Torvalds's avatar
Linus Torvalds committed
2246
	SBP2_DEBUG("sbp2_check_sbp2_response");
Linus Torvalds's avatar
Linus Torvalds committed
2247 2248 2249 2250 2251

	switch (SCpnt->cmnd[0]) {
		
		case INQUIRY:

Ben Collins's avatar
Ben Collins committed
2252 2253 2254 2255 2256 2257 2258 2259 2260
			/*
			 * If scsi_id->sbp2_device_type_and_lun is uninitialized, then fill 
			 * this information in from the inquiry response data. Lun is set to zero.
			 */
			if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
				SBP2_DEBUG("Creating sbp2_device_type_and_lun from scsi inquiry data");
				scsi_id->sbp2_device_type_and_lun = (scsi_buf[0] & 0x1f) << 16;
			}

Linus Torvalds's avatar
Linus Torvalds committed
2261 2262 2263 2264 2265 2266
			/*
			 * Make sure data length is ok. Minimum length is 36 bytes
			 */
			if (scsi_buf[4] == 0) {
				scsi_buf[4] = 36 - 5;
			}
Linus Torvalds's avatar
Linus Torvalds committed
2267 2268 2269 2270 2271

			/*
			 * Check for Simple Direct Access Device and change it to TYPE_DISK
			 */
			if ((scsi_buf[0] & 0x1f) == TYPE_SDAD) {
Linus Torvalds's avatar
Linus Torvalds committed
2272
				SBP2_DEBUG("Changing TYPE_SDAD to TYPE_DISK");
Linus Torvalds's avatar
Linus Torvalds committed
2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285
				scsi_buf[0] &= 0xe0;
			}

			/*
			 * Fix ansi revision and response data format
			 */
			scsi_buf[2] |= 2;
			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;

			break;

		case MODE_SENSE:

Ben Collins's avatar
Ben Collins committed
2286 2287
			if (sbp2_command_conversion_device_type(device_type)) {
			
Linus Torvalds's avatar
Linus Torvalds committed
2288
				SBP2_DEBUG("Modify mode sense response (10 byte version)");
Ben Collins's avatar
Ben Collins committed
2289

Linus Torvalds's avatar
Linus Torvalds committed
2290 2291 2292 2293 2294
				scsi_buf[0] = scsi_buf[1];	/* Mode data length */
				scsi_buf[1] = scsi_buf[2];	/* Medium type */
				scsi_buf[2] = scsi_buf[3];	/* Device specific parameter */
				scsi_buf[3] = scsi_buf[7];	/* Block descriptor length */
				memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]);
Ben Collins's avatar
Ben Collins committed
2295
	
Linus Torvalds's avatar
Linus Torvalds committed
2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315
			}

			break;

		case MODE_SELECT:

			/*
			 * TODO. Probably need to change mode select to 10 byte version
			 */

		default:
			break;
	}
	return;
}

/*
 * This function deals with status writes from the SBP-2 device
 */
static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
2316
				    quadlet_t *data, u64 addr, size_t length, u16 fl)
Linus Torvalds's avatar
Linus Torvalds committed
2317
{
2318 2319
	struct sbp2scsi_host_info *hi;
	struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
Ben Collins's avatar
Ben Collins committed
2320
	u32 id;
Linus Torvalds's avatar
Linus Torvalds committed
2321 2322 2323 2324
	Scsi_Cmnd *SCpnt = NULL;
	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
	struct sbp2_command_info *command;

Linus Torvalds's avatar
Linus Torvalds committed
2325
	SBP2_DEBUG("sbp2_handle_status_write");
Linus Torvalds's avatar
Linus Torvalds committed
2326

Ben Collins's avatar
Ben Collins committed
2327 2328
	sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr);

Linus Torvalds's avatar
Linus Torvalds committed
2329
	if (!host) {
Linus Torvalds's avatar
Linus Torvalds committed
2330
		SBP2_ERR("host is NULL - this is bad!");
Linus Torvalds's avatar
Linus Torvalds committed
2331 2332 2333
		return(RCODE_ADDRESS_ERROR);
	}

2334
	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
Linus Torvalds's avatar
Linus Torvalds committed
2335 2336

	if (!hi) {
Linus Torvalds's avatar
Linus Torvalds committed
2337
		SBP2_ERR("host info is NULL - this is bad!");
Linus Torvalds's avatar
Linus Torvalds committed
2338 2339 2340 2341
		return(RCODE_ADDRESS_ERROR);
	}

	/*
Ben Collins's avatar
Ben Collins committed
2342 2343
	 * Find our scsi_id structure by looking at the status fifo address written to by
	 * the sbp2 device.
Linus Torvalds's avatar
Linus Torvalds committed
2344
	 */
2345 2346 2347 2348 2349 2350 2351
	id = SBP2_STATUS_FIFO_OFFSET_TO_ENTRY((u32)(addr - SBP2_STATUS_FIFO_ADDRESS));
	list_for_each_entry(scsi_id_tmp, &hi->scsi_ids, scsi_list) {
		if (scsi_id_tmp->ne->nodeid == nodeid && scsi_id_tmp->ud->id == id) {
			scsi_id = scsi_id_tmp;
			break;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
2352 2353

	if (!scsi_id) {
Linus Torvalds's avatar
Linus Torvalds committed
2354
		SBP2_ERR("scsi_id is NULL - device is gone?");
Linus Torvalds's avatar
Linus Torvalds committed
2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373
		return(RCODE_ADDRESS_ERROR);
	}

	/*
	 * Put response into scsi_id status fifo... 
	 */
	memcpy(&scsi_id->status_block, data, length);

	/*
	 * Byte swap first two quadlets (8 bytes) of status for processing
	 */
	sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8);

	/*
	 * Handle command ORB status here if necessary. First, need to match status with command.
	 */
	command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo);
	if (command) {

Linus Torvalds's avatar
Linus Torvalds committed
2374
		SBP2_DEBUG("Found status for command ORB");
Linus Torvalds's avatar
Linus Torvalds committed
2375 2376 2377 2378 2379 2380
		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
				    sizeof(struct sbp2_command_orb),
				    PCI_DMA_BIDIRECTIONAL);
		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
				    sizeof(command->scatter_gather_element),
				    PCI_DMA_BIDIRECTIONAL);
Linus Torvalds's avatar
Linus Torvalds committed
2381 2382 2383 2384 2385 2386 2387 2388 2389 2390

		SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
		outstanding_orb_decr;

		/*
		 * Matched status with command, now grab scsi command pointers and check status
		 */
		SCpnt = command->Current_SCpnt;
		sbp2util_mark_command_completed(scsi_id, command);

Ben Collins's avatar
Ben Collins committed
2391
		if (SCpnt) {
Linus Torvalds's avatar
Linus Torvalds committed
2392 2393

			/*
Linus Torvalds's avatar
Linus Torvalds committed
2394
			 * See if the target stored any scsi status information
Linus Torvalds's avatar
Linus Torvalds committed
2395
			 */
Ben Collins's avatar
Ben Collins committed
2396
			if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) {
Linus Torvalds's avatar
Linus Torvalds committed
2397 2398 2399
				/*
				 * Translate SBP-2 status to SCSI sense data
				 */
Ben Collins's avatar
Ben Collins committed
2400
				SBP2_DEBUG("CHECK CONDITION");
Linus Torvalds's avatar
Linus Torvalds committed
2401
				scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
Linus Torvalds's avatar
Linus Torvalds committed
2402
			}
Linus Torvalds's avatar
Linus Torvalds committed
2403

Linus Torvalds's avatar
Linus Torvalds committed
2404
			/*
Ben Collins's avatar
Ben Collins committed
2405 2406
			 * Check to see if the dead bit is set. If so, we'll have to initiate
			 * a fetch agent reset.
Linus Torvalds's avatar
Linus Torvalds committed
2407
			 */
Ben Collins's avatar
Ben Collins committed
2408 2409
			if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) {

Linus Torvalds's avatar
Linus Torvalds committed
2410 2411 2412
				/*
				 * Initiate a fetch agent reset. 
				 */
Ben Collins's avatar
Ben Collins committed
2413
				SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
2414
                                sbp2_agent_reset(scsi_id, 0);
Linus Torvalds's avatar
Linus Torvalds committed
2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
			}

			SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
		}

		/*
		 * Check here to see if there are no commands in-use. If there are none, we can
		 * null out last orb so that next time around we write directly to the orb pointer... 
		 * Quick start saves one 1394 bus transaction.
		 */
		if (list_empty(&scsi_id->sbp2_command_orb_inuse)) {
			scsi_id->last_orb = NULL;
		}

Ben Collins's avatar
Ben Collins committed
2429 2430 2431 2432 2433 2434
	} else {
		
		/* 
		 * It's probably a login/logout/reconnect status.
		 */
		if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
2435
		    (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
Ben Collins's avatar
Ben Collins committed
2436 2437 2438 2439
		    (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
		    (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
			atomic_set(&scsi_id->sbp2_login_complete, 1);
		}
Linus Torvalds's avatar
Linus Torvalds committed
2440 2441
	}

Ben Collins's avatar
Ben Collins committed
2442 2443
	if (SCpnt) {

2444
		/* Complete the SCSI command. */
Ben Collins's avatar
Ben Collins committed
2445
		SBP2_DEBUG("Completing SCSI command");
2446 2447
		sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
					  command->Current_done);
Ben Collins's avatar
Ben Collins committed
2448 2449 2450
		SBP2_ORB_DEBUG("command orb completed");
	}

Linus Torvalds's avatar
Linus Torvalds committed
2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464
	return(RCODE_COMPLETE);
}


/**************************************
 * SCSI interface related section
 **************************************/

/*
 * This routine is the main request entry routine for doing I/O. It is 
 * called from the scsi stack directly.
 */
static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) 
{
2465 2466 2467
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
	struct sbp2scsi_host_info *hi;
Linus Torvalds's avatar
Linus Torvalds committed
2468

Linus Torvalds's avatar
Linus Torvalds committed
2469
	SBP2_DEBUG("sbp2scsi_queuecommand");
Linus Torvalds's avatar
Linus Torvalds committed
2470 2471

	/*
2472 2473
	 * If scsi_id is null, it means there is no device in this slot,
	 * so we should return selection timeout.
Linus Torvalds's avatar
Linus Torvalds committed
2474
	 */
2475
	if (!scsi_id) {
Linus Torvalds's avatar
Linus Torvalds committed
2476 2477
		SCpnt->result = DID_NO_CONNECT << 16;
		done (SCpnt);
2478
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2479 2480
	}

2481
	hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
2482

2483 2484
	if (!hi) {
		SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
Linus Torvalds's avatar
Linus Torvalds committed
2485 2486 2487 2488 2489 2490
		SCpnt->result = DID_NO_CONNECT << 16;
		done (SCpnt);
		return(0);
	}

	/*
Linus Torvalds's avatar
Linus Torvalds committed
2491 2492
	 * Until we handle multiple luns, just return selection time-out
	 * to any IO directed at non-zero LUNs
Linus Torvalds's avatar
Linus Torvalds committed
2493
	 */
2494
	if (SCpnt->device->lun) {
Linus Torvalds's avatar
Linus Torvalds committed
2495 2496 2497 2498 2499 2500
		SCpnt->result = DID_NO_CONNECT << 16;
		done (SCpnt);
		return(0);
	}

	/*
Linus Torvalds's avatar
Linus Torvalds committed
2501 2502
	 * Check for request sense command, and handle it here
	 * (autorequest sense)
Linus Torvalds's avatar
Linus Torvalds committed
2503 2504
	 */
	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
Linus Torvalds's avatar
Linus Torvalds committed
2505
		SBP2_DEBUG("REQUEST_SENSE");
Linus Torvalds's avatar
Linus Torvalds committed
2506 2507
		memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen);
		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
2508
		sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done);
Linus Torvalds's avatar
Linus Torvalds committed
2509 2510 2511 2512
		return(0);
	}

	/*
Ben Collins's avatar
Ben Collins committed
2513
	 * Check to see if we are in the middle of a bus reset.
Linus Torvalds's avatar
Linus Torvalds committed
2514
	 */
Linus Torvalds's avatar
Linus Torvalds committed
2515
	if (!hpsb_node_entry_valid(scsi_id->ne)) {
Linus Torvalds's avatar
Linus Torvalds committed
2516
		SBP2_ERR("Bus reset in progress - rejecting command");
Linus Torvalds's avatar
Linus Torvalds committed
2517 2518 2519 2520 2521 2522 2523 2524
		SCpnt->result = DID_BUS_BUSY << 16;
		done (SCpnt);
		return(0);
	}

	/*
	 * Try and send our SCSI command
	 */
2525
	if (sbp2_send_command(scsi_id, SCpnt, done)) {
Linus Torvalds's avatar
Linus Torvalds committed
2526
		SBP2_ERR("Error sending SCSI command");
2527 2528
		sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
					  SCpnt, done);
Linus Torvalds's avatar
Linus Torvalds committed
2529 2530 2531 2532 2533 2534
	}

	return(0);
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
2535 2536
 * This function is called in order to complete all outstanding SBP-2
 * commands (in case of resets, etc.).
Linus Torvalds's avatar
Linus Torvalds committed
2537
 */
2538
static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id, 
Linus Torvalds's avatar
Linus Torvalds committed
2539 2540
					   u32 status)
{
2541
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
2542 2543 2544
	struct list_head *lh;
	struct sbp2_command_info *command;

2545
	SBP2_DEBUG("sbp2scsi_complete_all_commands");
Linus Torvalds's avatar
Linus Torvalds committed
2546 2547

	while (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
Linus Torvalds's avatar
Linus Torvalds committed
2548
		SBP2_DEBUG("Found pending command to complete");
Linus Torvalds's avatar
Linus Torvalds committed
2549 2550
		lh = scsi_id->sbp2_command_orb_inuse.next;
		command = list_entry(lh, struct sbp2_command_info, list);
Linus Torvalds's avatar
Linus Torvalds committed
2551 2552 2553 2554 2555 2556
		pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
				    sizeof(struct sbp2_command_orb),
				    PCI_DMA_BIDIRECTIONAL);
		pci_dma_sync_single(hi->host->pdev, command->sge_dma,
				    sizeof(command->scatter_gather_element),
				    PCI_DMA_BIDIRECTIONAL);
Linus Torvalds's avatar
Linus Torvalds committed
2557
		sbp2util_mark_command_completed(scsi_id, command);
Ben Collins's avatar
Ben Collins committed
2558
		if (command->Current_SCpnt) {
Linus Torvalds's avatar
Linus Torvalds committed
2559 2560 2561 2562 2563 2564
			void (*done)(Scsi_Cmnd *) = command->Current_done;
			command->Current_SCpnt->result = status << 16;
			done (command->Current_SCpnt);
		}
	}

2565
	scsi_unblock_requests(scsi_id->scsi_host);
2566

Linus Torvalds's avatar
Linus Torvalds committed
2567 2568 2569 2570
	return;
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
2571
 * This function is called in order to complete a regular SBP-2 command.
Ben Collins's avatar
Ben Collins committed
2572 2573
 *
 * This can be called in interrupt context.
Linus Torvalds's avatar
Linus Torvalds committed
2574
 */
2575
static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
Ben Collins's avatar
Ben Collins committed
2576 2577
				      u32 scsi_status, Scsi_Cmnd *SCpnt,
				      void (*done)(Scsi_Cmnd *))
Linus Torvalds's avatar
Linus Torvalds committed
2578
{
Ben Collins's avatar
Ben Collins committed
2579 2580
	unsigned long flags;

Linus Torvalds's avatar
Linus Torvalds committed
2581
	SBP2_DEBUG("sbp2scsi_complete_command");
Linus Torvalds's avatar
Linus Torvalds committed
2582 2583 2584 2585 2586

	/*
	 * Sanity
	 */
	if (!SCpnt) {
Linus Torvalds's avatar
Linus Torvalds committed
2587
		SBP2_ERR("SCpnt is NULL");
Linus Torvalds's avatar
Linus Torvalds committed
2588 2589 2590 2591
		return;
	}

	/*
Linus Torvalds's avatar
Linus Torvalds committed
2592 2593 2594
	 * If a bus reset is in progress and there was an error, don't
	 * complete the command, just let it get retried at the end of the
	 * bus reset.
Linus Torvalds's avatar
Linus Torvalds committed
2595
	 */
Linus Torvalds's avatar
Linus Torvalds committed
2596
	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
Linus Torvalds's avatar
Linus Torvalds committed
2597
		SBP2_ERR("Bus reset in progress - retry command later");
Linus Torvalds's avatar
Linus Torvalds committed
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
		return;
	}
        
	/*
	 * Switch on scsi status
	 */
	switch (scsi_status) {
		case SBP2_SCSI_STATUS_GOOD:
			SCpnt->result = DID_OK;
			break;

		case SBP2_SCSI_STATUS_BUSY:
Linus Torvalds's avatar
Linus Torvalds committed
2610
			SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
Linus Torvalds's avatar
Linus Torvalds committed
2611 2612 2613 2614
			SCpnt->result = DID_BUS_BUSY << 16;
			break;

		case SBP2_SCSI_STATUS_CHECK_CONDITION:
Linus Torvalds's avatar
Linus Torvalds committed
2615
			SBP2_DEBUG("SBP2_SCSI_STATUS_CHECK_CONDITION");
Linus Torvalds's avatar
Linus Torvalds committed
2616 2617 2618 2619 2620
			SCpnt->result = CHECK_CONDITION << 1;

			/*
			 * Debug stuff
			 */
Linus Torvalds's avatar
Linus Torvalds committed
2621 2622
#if CONFIG_IEEE1394_SBP2_DEBUG >= 1
			print_command (SCpnt->cmnd);
Linus Torvalds's avatar
Linus Torvalds committed
2623
			print_sense("bh", SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
2624
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2625 2626 2627 2628

			break;

		case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
Linus Torvalds's avatar
Linus Torvalds committed
2629
			SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
Linus Torvalds's avatar
Linus Torvalds committed
2630
			SCpnt->result = DID_NO_CONNECT << 16;
Linus Torvalds's avatar
Linus Torvalds committed
2631
			print_command (SCpnt->cmnd);
Linus Torvalds's avatar
Linus Torvalds committed
2632 2633 2634 2635 2636
			break;

		case SBP2_SCSI_STATUS_CONDITION_MET:
		case SBP2_SCSI_STATUS_RESERVATION_CONFLICT:
		case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
Linus Torvalds's avatar
Linus Torvalds committed
2637
			SBP2_ERR("Bad SCSI status = %x", scsi_status);
Linus Torvalds's avatar
Linus Torvalds committed
2638
			SCpnt->result = DID_ERROR << 16;
Linus Torvalds's avatar
Linus Torvalds committed
2639
			print_command (SCpnt->cmnd);
Linus Torvalds's avatar
Linus Torvalds committed
2640 2641 2642
			break;

		default:
Linus Torvalds's avatar
Linus Torvalds committed
2643
			SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
Linus Torvalds's avatar
Linus Torvalds committed
2644 2645 2646 2647 2648 2649 2650
			SCpnt->result = DID_ERROR << 16;
	}

	/*
	 * Take care of any sbp2 response data mucking here (RBC stuff, etc.)
	 */
	if (SCpnt->result == DID_OK) {
Ben Collins's avatar
Ben Collins committed
2651
		sbp2_check_sbp2_response(scsi_id, SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
2652 2653 2654
	}

	/*
Linus Torvalds's avatar
Linus Torvalds committed
2655 2656
	 * If a bus reset is in progress and there was an error, complete
	 * the command as busy so that it will get retried.
Linus Torvalds's avatar
Linus Torvalds committed
2657
	 */
Linus Torvalds's avatar
Linus Torvalds committed
2658
	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
Linus Torvalds's avatar
Linus Torvalds committed
2659
		SBP2_ERR("Completing command with busy (bus reset)");
Linus Torvalds's avatar
Linus Torvalds committed
2660 2661 2662 2663
		SCpnt->result = DID_BUS_BUSY << 16;
	}

	/*
Linus Torvalds's avatar
Linus Torvalds committed
2664 2665 2666
	 * If a unit attention occurs, return busy status so it gets
	 * retried... it could have happened because of a 1394 bus reset
	 * or hot-plug...
Linus Torvalds's avatar
Linus Torvalds committed
2667
	 */
Ben Collins's avatar
Ben Collins committed
2668 2669 2670
#if 0
	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && 
	    (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
Ben Collins's avatar
Ben Collins committed
2671
		SBP2_DEBUG("UNIT ATTENTION - return busy");
Linus Torvalds's avatar
Linus Torvalds committed
2672 2673
		SCpnt->result = DID_BUS_BUSY << 16;
	}
Ben Collins's avatar
Ben Collins committed
2674
#endif
Linus Torvalds's avatar
Linus Torvalds committed
2675 2676 2677 2678

	/*
	 * Tell scsi stack that we're done with this command
	 */
2679
	spin_lock_irqsave(scsi_id->scsi_host->host_lock,flags);
Linus Torvalds's avatar
Linus Torvalds committed
2680
	done (SCpnt);
2681
	spin_unlock_irqrestore(scsi_id->scsi_host->host_lock,flags);
Linus Torvalds's avatar
Linus Torvalds committed
2682 2683 2684 2685 2686

	return;
}

/*
Linus Torvalds's avatar
Linus Torvalds committed
2687 2688
 * Called by scsi stack when something has really gone wrong.  Usually
 * called when a command has timed-out for some reason.
Linus Torvalds's avatar
Linus Torvalds committed
2689 2690 2691
 */
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) 
{
2692 2693 2694
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
	struct sbp2scsi_host_info *hi = scsi_id->hi;
Linus Torvalds's avatar
Linus Torvalds committed
2695 2696
	struct sbp2_command_info *command;

Linus Torvalds's avatar
Linus Torvalds committed
2697
	SBP2_ERR("aborting sbp2 command");
Linus Torvalds's avatar
Linus Torvalds committed
2698 2699
	print_command (SCpnt->cmnd);
        
Linus Torvalds's avatar
Linus Torvalds committed
2700 2701 2702
	if (scsi_id) {

		/*
Linus Torvalds's avatar
Linus Torvalds committed
2703
		 * Right now, just return any matching command structures
Ben Collins's avatar
Ben Collins committed
2704
		 * to the free pool.
Linus Torvalds's avatar
Linus Torvalds committed
2705
		 */
Ben Collins's avatar
Ben Collins committed
2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721
		command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
		if (command) {
			SBP2_DEBUG("Found command to abort");
			pci_dma_sync_single(hi->host->pdev,
					    command->command_orb_dma,
					    sizeof(struct sbp2_command_orb),
					    PCI_DMA_BIDIRECTIONAL);
			pci_dma_sync_single(hi->host->pdev,
					    command->sge_dma,
					    sizeof(command->scatter_gather_element),
					    PCI_DMA_BIDIRECTIONAL);
			sbp2util_mark_command_completed(scsi_id, command);
			if (command->Current_SCpnt) {
				void (*done)(Scsi_Cmnd *) = command->Current_done;
				command->Current_SCpnt->result = DID_ABORT << 16;
				done (command->Current_SCpnt);
Linus Torvalds's avatar
Linus Torvalds committed
2722
			}
Ben Collins's avatar
Ben Collins committed
2723
		}
Linus Torvalds's avatar
Linus Torvalds committed
2724 2725 2726 2727

		/*
		 * Initiate a fetch agent reset. 
		 */
2728 2729
		sbp2_agent_reset(scsi_id, 0);
		sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);		
Linus Torvalds's avatar
Linus Torvalds committed
2730 2731
	}

Linus Torvalds's avatar
Linus Torvalds committed
2732
	return(SUCCESS);
Linus Torvalds's avatar
Linus Torvalds committed
2733 2734 2735 2736 2737
}

/*
 * Called by scsi stack when something has really gone wrong.
 */
Linus Torvalds's avatar
Linus Torvalds committed
2738
static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) 
Linus Torvalds's avatar
Linus Torvalds committed
2739
{
2740 2741
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
Linus Torvalds's avatar
Linus Torvalds committed
2742

Linus Torvalds's avatar
Linus Torvalds committed
2743
	SBP2_ERR("reset requested");
Linus Torvalds's avatar
Linus Torvalds committed
2744

Ben Collins's avatar
Ben Collins committed
2745
	if (scsi_id) {
Ben Collins's avatar
Ben Collins committed
2746
		SBP2_ERR("Generating sbp2 fetch agent reset");
2747
		sbp2_agent_reset(scsi_id, 0);
Linus Torvalds's avatar
Linus Torvalds committed
2748 2749
	}

Linus Torvalds's avatar
Linus Torvalds committed
2750
	return(SUCCESS);
Linus Torvalds's avatar
Linus Torvalds committed
2751 2752
}

Ben Collins's avatar
Ben Collins committed
2753
static const char *sbp2scsi_info (struct Scsi_Host *host)
2754
{
2755
        return "SCSI emulation for IEEE-1394 SBP-2 Devices";
Ben Collins's avatar
Ben Collins committed
2756 2757
}

2758
static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, char *buf)
2759 2760 2761
{
	struct scsi_device *sdev;
	struct scsi_id_instance_data *scsi_id;
2762
	int lun;
2763 2764 2765 2766

	if (!(sdev = to_scsi_device(dev)))
		return 0;

2767
	if (!(scsi_id = (struct scsi_id_instance_data *)sdev->host->hostdata[0]))
2768 2769
		return 0;

2770 2771 2772 2773
	if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED)
		lun = 0;
	else
		lun = ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
2774

2775 2776 2777 2778
	return sprintf(buf, "%016Lx:%d:%d\n", (unsigned long long)scsi_id->ne->guid,
		       scsi_id->ud->id, lun);
}
static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
2779 2780

static struct device_attribute *sbp2_sysfs_sdev_attrs[] = {
2781
	&dev_attr_ieee1394_id,
2782 2783 2784
	NULL
};

Ben Collins's avatar
Ben Collins committed
2785
MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
Linus Torvalds's avatar
Linus Torvalds committed
2786 2787 2788 2789 2790 2791
MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
MODULE_LICENSE("GPL");

/* SCSI host template */
static Scsi_Host_Template scsi_driver_template = {
Ben Collins's avatar
Ben Collins committed
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
	.module =			THIS_MODULE,
	.name =				"SBP-2 IEEE-1394",
	.proc_name =			SBP2_DEVICE_NAME,
	.info =				sbp2scsi_info,
	.queuecommand =			sbp2scsi_queuecommand,
	.eh_abort_handler =		sbp2scsi_abort,
	.eh_device_reset_handler =	sbp2scsi_reset,
	.eh_bus_reset_handler =		sbp2scsi_reset,
	.eh_host_reset_handler =	sbp2scsi_reset,
	.this_id =			-1,
	.sg_tablesize =			SG_ALL,
	.use_clustering =		ENABLE_CLUSTERING,
2804 2805
	.cmd_per_lun =			SBP2_MAX_CMDS,
	.can_queue = 			SBP2_MAX_CMDS,
Ben Collins's avatar
Ben Collins committed
2806
	.emulated =			1,
2807
	.sdev_attrs =			sbp2_sysfs_sdev_attrs,
Linus Torvalds's avatar
Linus Torvalds committed
2808 2809 2810 2811 2812 2813
};

static int sbp2_module_init(void)
{
	SBP2_DEBUG("sbp2_module_init");

2814 2815
	printk(KERN_INFO "sbp2: %s\n", version);

2816
	/* Module load debug option to force one command at a time (serializing I/O) */
2817
	if (serialize_io) {
Linus Torvalds's avatar
Linus Torvalds committed
2818
		SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
Linus Torvalds's avatar
Linus Torvalds committed
2819 2820
		scsi_driver_template.can_queue = 1;
		scsi_driver_template.cmd_per_lun = 1;
Linus Torvalds's avatar
Linus Torvalds committed
2821 2822
	}

2823
	/* Set max sectors (module load option). Default is 255 sectors. */
2824
	scsi_driver_template.max_sectors = max_sectors;
Linus Torvalds's avatar
Linus Torvalds committed
2825

Ben Collins's avatar
Ben Collins committed
2826

2827 2828
	/* Register our high level driver with 1394 stack */
	hpsb_register_highlevel(&sbp2_highlevel);
Linus Torvalds's avatar
Linus Torvalds committed
2829

Ben Collins's avatar
Ben Collins committed
2830
	hpsb_register_protocol(&sbp2_driver);
2831

Linus Torvalds's avatar
Linus Torvalds committed
2832
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
2833 2834
}

Linus Torvalds's avatar
Linus Torvalds committed
2835
static void __exit sbp2_module_exit(void)
Linus Torvalds's avatar
Linus Torvalds committed
2836
{
Linus Torvalds's avatar
Linus Torvalds committed
2837
	SBP2_DEBUG("sbp2_module_exit");
Linus Torvalds's avatar
Linus Torvalds committed
2838

Ben Collins's avatar
Ben Collins committed
2839
	hpsb_unregister_protocol(&sbp2_driver);
2840 2841

	hpsb_unregister_highlevel(&sbp2_highlevel);
Linus Torvalds's avatar
Linus Torvalds committed
2842
}
Linus Torvalds's avatar
Linus Torvalds committed
2843

Linus Torvalds's avatar
Linus Torvalds committed
2844 2845
module_init(sbp2_module_init);
module_exit(sbp2_module_exit);