i2o_scsi.c revision 0ea7154fbc740e8c44f6175fc44c4e56fbbbdc0f
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2, or (at your option) any
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * later version.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For the avoidance of doubt the "preferred form" of this code is one which
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is in an open non patent encumbered format. Where cryptographic key signing
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forms part of the process of creating an executable the information
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including keys needed to generate an equivalently functional executable
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are deemed to be part of the source code.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Complications for I2O scsi
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	o	Each (bus,lun) is a logical device in I2O. We keep a map
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		table. We spoof failed selection for unmapped units
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	o	Request sense buffers can come back for free.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	o	Scatter gather is a bit dynamic. We have to investigate at
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		setup time.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	o	Some of our resources are dynamically shared. The i2o core
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		needs a message reservation protocol to avoid swap v net
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		deadlocking. We need to back off queue requests.
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	In general the firmware wants to help. Where its help isn't performance
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	useful we just ignore the aid. Its not worth the code in truth.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes/additions:
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Steve Ralston:
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Scatter gather now works
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Minor fixes for 2.6.
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To Do:
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	64bit cleanups
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Fix the resource management problems.
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/prefetch.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2o.h>
57b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#include <linux/scatterlist.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atomic.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h>
68b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#include <scsi/sg.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OSM_NAME	"scsi-osm"
712e1973a3cd0b9fe31469be62df3583bdc5a34f51Markus Lidel#define OSM_VERSION	"1.316"
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OSM_DESCRIPTION	"I2O SCSI Peripheral OSM"
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_driver i2o_scsi_driver;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidelstatic unsigned int i2o_scsi_max_id = 16;
77b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidelstatic unsigned int i2o_scsi_max_lun = 255;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct i2o_scsi_host {
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *scsi_host;	/* pointer to the SCSI host */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *iop;	/* pointer to the I2O controller */
82b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	unsigned int lun;	/* lun's used for block devices */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *channel[0];	/* channel->i2o_dev mapping table */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template i2o_scsi_host_template;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2O_SCSI_CAN_QUEUE	4
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCSI OSM class handling definition */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_class_id i2o_scsi_class_id[] = {
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{I2O_CLASS_SCSI_PERIPHERAL},
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{I2O_CLASS_END}
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_scsi_host *i2o_shost;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *i2o_dev;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *scsi_host;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_channel = 0;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t size;
105b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	u16 body_size = 6;
106b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
107b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC
108b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	if (c->adaptec)
109b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		body_size = 8;
110b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(i2o_dev, &c->devices, list)
113f10378fff658f61307496e0ae00095041725cf07Markus Lidel	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
114793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
115b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		    && (type == 0x01))	/* SCSI bus */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			max_channel++;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!max_channel) {
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("no channels found on %s\n", c->name);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-EFAULT);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = max_channel * sizeof(struct i2o_device *)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    + sizeof(struct i2o_scsi_host);
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!scsi_host) {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("Could not allocate SCSI host\n");
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host->max_channel = max_channel - 1;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host->max_id = i2o_scsi_max_id;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host->max_lun = i2o_scsi_max_lun;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host->this_id = c->unit;
137b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost->scsi_host = scsi_host;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost->iop = c;
142b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	i2o_shost->lun = 1;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 0;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(i2o_dev, &c->devices, list)
146f10378fff658f61307496e0ae00095041725cf07Markus Lidel	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
147793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
148b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		    && (type == 0x01))	/* only SCSI bus */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i2o_shost->channel[i++] = i2o_dev;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i >= max_channel)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i2o_shost;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_get_host - Get an I2O SCSI host
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@c: I2O controller to for which to get the SCSI host
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	If the I2O controller already exists as SCSI host, the SCSI host
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	is returned, otherwise the I2O controller is added to the SCSI
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	core.
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns pointer to the I2O SCSI host on success or NULL on failure.
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return c->driver_data[i2o_scsi_driver.context];
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_remove - Remove I2O device from SCSI core
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@dev: device which should be removed
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Removes the I2O device from the SCSI core again.
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns 0 on success.
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_remove(struct device *dev)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *i2o_dev = to_i2o_device(dev);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c = i2o_dev->iop;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_scsi_host *i2o_shost;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_device *scsi_dev;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel	osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
189f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost = i2o_scsi_get_host(c);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    if (scsi_dev->hostdata == i2o_dev) {
194f10378fff658f61307496e0ae00095041725cf07Markus Lidel		sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_remove_device(scsi_dev);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_device_put(scsi_dev);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_probe - verify if dev is a I2O SCSI device and install it
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@dev: device to verify if it is a I2O SCSI device
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Retrieve channel, id and lun for I2O device. If everthing goes well
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	register the I2O device as SCSI device on the I2O SCSI controller.
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns 0 on success or negative error code on failure.
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_probe(struct device *dev)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *i2o_dev = to_i2o_device(dev);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c = i2o_dev->iop;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_scsi_host *i2o_shost;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *scsi_host;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *parent;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_device *scsi_dev;
220b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	u32 id = -1;
221b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	u64 lun = -1;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int channel = -1;
2233889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik	int i, rc;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost = i2o_scsi_get_host(c);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!i2o_shost)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host = i2o_shost->scsi_host;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	switch (i2o_dev->lct_data.class_id) {
232b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
233b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	case I2O_CLASS_EXECUTIVE:
234b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC
235b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		if (c->adaptec) {
236b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			u8 type;
237b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			struct i2o_device *d = i2o_shost->channel[0];
238b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
239793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel			if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1)
240b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			    && (type == 0x01))	/* SCSI bus */
241793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel				if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
242b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel					channel = 0;
243b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel					if (i2o_dev->lct_data.class_id ==
244b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel					    I2O_CLASS_RANDOM_BLOCK_STORAGE)
245793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel						lun =
246793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel						    cpu_to_le64(i2o_shost->
247793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel								lun++);
248b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel					else
249b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel						lun = 0;
250b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel				}
251b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		}
252b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif
253b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		break;
254b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
255b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	case I2O_CLASS_SCSI_PERIPHERAL:
256793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4))
257b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			return -EFAULT;
258b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
259793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8))
260b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			return -EFAULT;
261b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
262b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
263b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		if (!parent) {
264b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			osm_warn("can not find parent of device %03x\n",
265b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel				 i2o_dev->lct_data.tid);
266b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			return -EFAULT;
267b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		}
268b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
269b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
270b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			if (i2o_shost->channel[i] == parent)
271b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel				channel = i;
272b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		break;
273b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
274b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	default:
275b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		return -EFAULT;
276b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	}
277b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
278b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	if (channel == -1) {
279b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		osm_warn("can not find channel of device %03x\n",
280b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			 i2o_dev->lct_data.tid);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
282b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
284793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel	if (le32_to_cpu(id) >= scsi_host->max_id) {
285793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)",
286793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel			 le32_to_cpu(id), scsi_host->max_id);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
290793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel	if (le64_to_cpu(lun) >= scsi_host->max_lun) {
291793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		osm_warn("SCSI device lun (%lu) >= max_lun of I2O host (%d)",
292793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel			 (long unsigned int)le64_to_cpu(lun),
293793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel			 scsi_host->max_lun);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_dev =
298793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel	    __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id),
299793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel			      le64_to_cpu(lun), i2o_dev);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301f10378fff658f61307496e0ae00095041725cf07Markus Lidel	if (IS_ERR(scsi_dev)) {
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("can not add SCSI device %03x\n",
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 i2o_dev->lct_data.tid);
304f10378fff658f61307496e0ae00095041725cf07Markus Lidel		return PTR_ERR(scsi_dev);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3073889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik	rc = sysfs_create_link(&i2o_dev->device.kobj,
3083889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik			       &scsi_dev->sdev_gendev.kobj, "scsi");
3093889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik	if (rc)
3103889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik		goto err;
311f10378fff658f61307496e0ae00095041725cf07Markus Lidel
312dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel	osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %ld\n",
313793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel		 i2o_dev->lct_data.tid, channel, le32_to_cpu(id),
314dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel		 (long unsigned int)le64_to_cpu(lun));
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3173889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik
3183889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzikerr:
3193889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik	scsi_remove_device(scsi_dev);
3203889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik	return rc;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *i2o_scsi_info(struct Scsi_Host *SChost)
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_scsi_host *hostdata;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return hostdata->iop->name;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_reply - SCSI OSM message reply handler
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@c: controller issuing the reply
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@m: message id for flushing
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@msg: the message from the controller
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Process reply messages (interrupts in normal scsi controller think).
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	We can get a variety of messages to process. The normal path is
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	scsi command completions. We must also deal with IOP failures,
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the reply to a bus reset and the reply to a LUN query.
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns 0 on success and if the reply should not be flushed or > 0
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	on success and if the reply should be flushed. Returns negative error
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	code on failure and if the reply should be flushed.
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_reply(struct i2o_controller *c, u32 m,
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  struct i2o_message *msg)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scsi_cmnd *cmd;
3499e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	u32 error;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device *dev;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
3539e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	if (unlikely(!cmd)) {
3549e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		osm_err("NULL reply received!\n");
3559e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		return -1;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      Low byte is device status, next is adapter status,
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      (then one byte reserved), then request status.
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3629e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	error = le32_to_cpu(msg->body[0]);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3649e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	osm_debug("Completed %ld\n", cmd->serial_number);
3659e87545f06930c1d294423a8091d1077e7444a47Markus Lidel
3669e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	cmd->result = error & 0xff;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3689e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	 * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
3699e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	 * the SCSI layer handle the error
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3719e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	if (cmd->result)
3729e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		memcpy(cmd->sense_buffer, &msg->body[3],
3739e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		       min(sizeof(cmd->sense_buffer), (size_t) 40));
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3759e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	/* only output error code if AdapterStatus is not HBA_SUCCESS */
3769e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	if ((error >> 8) & 0xff)
3779e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		osm_err("SCSI error %08x\n", error);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3799e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	dev = &c->pdev->dev;
3800ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori
3810ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori	scsi_dma_unmap(cmd);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3839e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	cmd->scsi_done(cmd);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3859e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	return 1;
3869e87545f06930c1d294423a8091d1077e7444a47Markus Lidel};
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3889e87545f06930c1d294423a8091d1077e7444a47Markus Lidel/**
3899e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	i2o_scsi_notify_device_add - Retrieve notifications of added devices
3909e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	@i2o_dev: the I2O device which was added
3919e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *
3929e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	If a I2O device is added we catch the notification, because I2O classes
3939e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	other then SCSI peripheral will not be received through
3949e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	i2o_scsi_probe().
3959e87545f06930c1d294423a8091d1077e7444a47Markus Lidel */
3969e87545f06930c1d294423a8091d1077e7444a47Markus Lidelstatic void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
3979e87545f06930c1d294423a8091d1077e7444a47Markus Lidel{
3989e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	switch (i2o_dev->lct_data.class_id) {
3999e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	case I2O_CLASS_EXECUTIVE:
4009e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
4019e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		i2o_scsi_probe(&i2o_dev->device);
4029e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		break;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4049e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	default:
4059e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		break;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4079e87545f06930c1d294423a8091d1077e7444a47Markus Lidel};
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4099e87545f06930c1d294423a8091d1077e7444a47Markus Lidel/**
410d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap *	i2o_scsi_notify_device_remove - Retrieve notifications of removed devices
4119e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	@i2o_dev: the I2O device which was removed
4129e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *
4139e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	If a I2O device is removed, we catch the notification to remove the
4149e87545f06930c1d294423a8091d1077e7444a47Markus Lidel *	corresponding SCSI device.
4159e87545f06930c1d294423a8091d1077e7444a47Markus Lidel */
4169e87545f06930c1d294423a8091d1077e7444a47Markus Lidelstatic void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
4179e87545f06930c1d294423a8091d1077e7444a47Markus Lidel{
4189e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	switch (i2o_dev->lct_data.class_id) {
4199e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	case I2O_CLASS_EXECUTIVE:
4209e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
4219e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		i2o_scsi_remove(&i2o_dev->device);
4229e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		break;
423f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel
4249e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	default:
4259e87545f06930c1d294423a8091d1077e7444a47Markus Lidel		break;
4269e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
430d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap *	i2o_scsi_notify_controller_add - Retrieve notifications of added controllers
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@c: the controller which was added
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	If a I2O controller is added, we catch the notification to add a
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	corresponding Scsi_Host.
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i2o_scsi_notify_controller_add(struct i2o_controller *c)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_scsi_host *i2o_shost;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost = i2o_scsi_host_alloc(c);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(i2o_shost)) {
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_err("Could not initialize SCSI host\n");
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_err("Could not add SCSI host\n");
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		scsi_host_put(i2o_shost->scsi_host);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c->driver_data[i2o_scsi_driver.context] = i2o_shost;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_debug("new I2O SCSI host added\n");
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
460d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap *	i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@c: the controller which was removed
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	If a I2O controller is removed, we catch the notification to remove the
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	corresponding Scsi_Host.
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_scsi_host *i2o_shost;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_shost = i2o_scsi_get_host(c);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!i2o_shost)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c->driver_data[i2o_scsi_driver.context] = NULL;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_remove_host(i2o_shost->scsi_host);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	scsi_host_put(i2o_shost->scsi_host);
477f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel	osm_debug("I2O SCSI host removed\n");
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCSI OSM driver struct */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_driver i2o_scsi_driver = {
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = OSM_NAME,
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.reply = i2o_scsi_reply,
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.classes = i2o_scsi_class_id,
4859e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	.notify_device_add = i2o_scsi_notify_device_add,
4869e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	.notify_device_remove = i2o_scsi_notify_device_remove,
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.notify_controller_add = i2o_scsi_notify_controller_add,
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.notify_controller_remove = i2o_scsi_notify_controller_remove,
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.driver = {
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   .probe = i2o_scsi_probe,
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   .remove = i2o_scsi_remove,
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   },
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_queuecommand - queue a SCSI command
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@SCpnt: scsi command pointer
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@done: callback for completion
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Issue a scsi command asynchronously. Return 0 on success or 1 if
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	we hit an error (normally message queue congestion). The only
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	minor complication here is that I2O deals with the device addressing
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	so we have to map the bus/dev/lun back to an I2O handle as well
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	as faking absent devices ourself.
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Locks: takes the controller lock on error path only
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 void (*done) (struct scsi_cmnd *))
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *i2o_dev;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tid;
515a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
516f10378fff658f61307496e0ae00095041725cf07Markus Lidel	/*
517f10378fff658f61307496e0ae00095041725cf07Markus Lidel	 * ENABLE_DISCONNECT
518f10378fff658f61307496e0ae00095041725cf07Markus Lidel	 * SIMPLE_TAG
519f10378fff658f61307496e0ae00095041725cf07Markus Lidel	 * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
520f10378fff658f61307496e0ae00095041725cf07Markus Lidel	 */
521f10378fff658f61307496e0ae00095041725cf07Markus Lidel	u32 scsi_flags = 0x20a00000;
522b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	u32 sgl_offset;
523a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	u32 *mptr;
524b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	u32 cmd = I2O_CMD_SCSI_EXEC << 24;
525b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	int rc = 0;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      Do the incoming paperwork
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_dev = SCpnt->device->hostdata;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_dev->iop;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCpnt->scsi_done = done;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(!i2o_dev)) {
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("no I2O device in request\n");
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->result = DID_NO_CONNECT << 16;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		done(SCpnt);
539b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		goto exit;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tid = i2o_dev->lct_data.tid;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_debug("qcmd: Tid = %03x\n", tid);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_debug("Real scsi messages.\n");
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      Put together a scsi execscb message
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (SCpnt->sc_data_direction) {
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DMA_NONE:
552f10378fff658f61307496e0ae00095041725cf07Markus Lidel		/* DATA NO XFER */
553b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		sgl_offset = SGL_OFFSET_0;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DMA_TODEVICE:
557f10378fff658f61307496e0ae00095041725cf07Markus Lidel		/* DATA OUT (iop-->dev) */
558f10378fff658f61307496e0ae00095041725cf07Markus Lidel		scsi_flags |= 0x80000000;
559b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		sgl_offset = SGL_OFFSET_10;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DMA_FROMDEVICE:
563f10378fff658f61307496e0ae00095041725cf07Markus Lidel		/* DATA IN  (iop<--dev) */
564f10378fff658f61307496e0ae00095041725cf07Markus Lidel		scsi_flags |= 0x40000000;
565b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		sgl_offset = SGL_OFFSET_10;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Unknown - kill the command */
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->result = DID_NO_CONNECT << 16;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		done(SCpnt);
572b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		goto exit;
573b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	}
574b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
575b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	/*
576b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	 *      Obtain an I2O message. If there are none free then
577b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	 *      throw it back to the scsi layer
578b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	 */
579b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
580a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get(c);
581a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg)) {
582b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		rc = SCSI_MLQUEUE_HOST_BUSY;
583b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		goto exit;
584b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	}
585b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
586b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	mptr = &msg->body[0];
587b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
588beb40487508290f5d6565598c60a3f44261beef2Christoph Hellwig#if 0 /* this code can't work */
589b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC
590b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	if (c->adaptec) {
591b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		u32 adpt_flags = 0;
592b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
593b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
594b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			i2o_sg_io_hdr_t __user *usr_ptr =
595b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			    ((Sg_request *) (SCpnt->sc_request->
596b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel					     upper_private_data))->header.
597b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			    usr_ptr;
598b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
599b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			if (usr_ptr)
600b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel				get_user(adpt_flags, &usr_ptr->flags);
601b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		}
602b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
603b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		switch (i2o_dev->lct_data.class_id) {
604b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		case I2O_CLASS_EXECUTIVE:
605b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
606b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			/* interpret flag has to be set for executive */
607b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
608b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			break;
609b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
610b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		default:
611b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			break;
612b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		}
613b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
614b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		/*
615b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		 * for Adaptec controllers we use the PRIVATE command, because
616b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		 * the normal SCSI EXEC doesn't support all SCSI commands on
617b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		 * all controllers (for example READ CAPACITY).
618b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		 */
619b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		if (sgl_offset == SGL_OFFSET_10)
620b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel			sgl_offset = SGL_OFFSET_12;
621b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		cmd = I2O_CMD_PRIVATE << 24;
622a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		*mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
623a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		*mptr++ = cpu_to_le32(adpt_flags | tid);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
625b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif
626beb40487508290f5d6565598c60a3f44261beef2Christoph Hellwig#endif
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
628a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
629a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We want the SCSI control block back */
632a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt));
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* LSI_920_PCI_QUIRK
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      Intermittant observations of msg frame word data corruption
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      observed on msg[4] after:
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *        WRITE, READ-MODIFY-WRITE
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      operations.  19990606 -sralston
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *      (Hence we build this word via tag. Its good practice anyway
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *       we don't want fetches over PCI needlessly)
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attach tags to the devices */
6469e87545f06930c1d294423a8091d1077e7444a47Markus Lidel	/* FIXME: implement
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   if(SCpnt->device->tagged_supported) {
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   scsi_flags |= 0x01000000;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   else if(SCpnt->tag == ORDERED_QUEUE_TAG)
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   scsi_flags |= 0x01800000;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   }
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
655a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	*mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Write SCSI command into the message - always 16 byte block */
658a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	memcpy(mptr, SCpnt->cmnd, 16);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mptr += 4;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	if (sgl_offset != SGL_OFFSET_0) {
662b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		/* write size of data addressed by SGL */
6630ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori		*mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
664b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
665b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel		/* Now fill in the SGList and command */
6660ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori
6670ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori		if (scsi_sg_count(SCpnt)) {
6680ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori			if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
6690ea7154fbc740e8c44f6175fc44c4e56fbbbdc0fFUJITA Tomonori					    scsi_sg_count(SCpnt),
670b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel					    SCpnt->sc_data_direction, &mptr))
671b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel				goto nomem;
672f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel		}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Stick the headers on */
676a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] =
677a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Queue the message */
680a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	i2o_msg_post(c, msg);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_debug("Issued %ld\n", SCpnt->serial_number);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
685b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
686b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel      nomem:
687b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	rc = -ENOMEM;
688a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	i2o_msg_nop(c, msg);
689b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel
690b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel      exit:
691b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel	return rc;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_abort - abort a running command
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@SCpnt: command to abort
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Ask the I2O controller to abort a command. This is an asynchrnous
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	process and our callback handler will see the command complete with an
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	aborted message if it succeeds.
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns 0 if the command is successfully aborted or negative error code
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	on failure.
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *i2o_dev;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
709a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tid;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status = FAILED;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_warn("Aborting command block.\n");
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_dev = SCpnt->device->hostdata;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_dev->iop;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tid = i2o_dev->lct_data.tid;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
719a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
720a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg))
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SCSI_MLQUEUE_HOST_BUSY;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
723a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
724a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] =
725a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
726a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
728e22bec266cd6f540da2a61db216914c3473135ccMarkus Lidel	if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = SUCCESS;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return status;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_bios_param	-	Invent disk geometry
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@sdev: scsi device
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@dev: block layer device
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@capacity: size in sectors
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@ip: geometry array
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
741d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap *	This is anyone's guess quite frankly. We use the same rules everyone
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	else appears to and hope. It seems to work.
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_bios_param(struct scsi_device *sdev,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct block_device *dev, sector_t capacity,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       int *ip)
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = capacity;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ip[0] = 64;		/* heads                        */
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ip[1] = 32;		/* sectors                      */
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ip[0] = 255;	/* heads                        */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ip[1] = 63;	/* sectors                      */
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ip[2] = size / (255 * 63);	/* cylinders                    */
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template i2o_scsi_host_template = {
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_name = OSM_NAME,
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = OSM_DESCRIPTION,
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = i2o_scsi_info,
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queuecommand = i2o_scsi_queuecommand,
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_abort_handler = i2o_scsi_abort,
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bios_param = i2o_scsi_bios_param,
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.can_queue = I2O_SCSI_CAN_QUEUE,
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sg_tablesize = 8,
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmd_per_lun = 6,
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.use_clustering = ENABLE_CLUSTERING,
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_init - SCSI OSM initialization function
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Register SCSI OSM into I2O core.
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns 0 on success or negative error code on failure.
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init i2o_scsi_init(void)
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Register SCSI OSM into I2O core */
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = i2o_driver_register(&i2o_scsi_driver);
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_err("Could not register SCSI driver\n");
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	i2o_scsi_exit - SCSI OSM exit function
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Unregisters SCSI OSM from I2O core.
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit i2o_scsi_exit(void)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Unregister I2O SCSI OSM from I2O core */
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_driver_unregister(&i2o_scsi_driver);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Red Hat Software");
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(OSM_DESCRIPTION);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(OSM_VERSION);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(i2o_scsi_init);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(i2o_scsi_exit);
816