#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/i2o.h>
+#include <linux/scatterlist.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_request.h>
+#include <scsi/sg.h>
+#include <scsi/sg_request.h>
-#define VERSION_STRING "Version 0.1.2"
+#define OSM_NAME "scsi-osm"
+#define OSM_VERSION "1.316"
+#define OSM_DESCRIPTION "I2O SCSI Peripheral OSM"
static struct i2o_driver i2o_scsi_driver;
-static int i2o_scsi_max_id = 16;
-static int i2o_scsi_max_lun = 8;
+static unsigned int i2o_scsi_max_id = 16;
+static unsigned int i2o_scsi_max_lun = 255;
struct i2o_scsi_host {
struct Scsi_Host *scsi_host; /* pointer to the SCSI host */
struct i2o_controller *iop; /* pointer to the I2O controller */
+ unsigned int lun; /* lun's used for block devices */
struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */
};
u8 type;
int i;
size_t size;
- i2o_status_block *sb;
+ u16 body_size = 6;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec)
+ body_size = 8;
+#endif
list_for_each_entry(i2o_dev, &c->devices, list)
- if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
- if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* SCSI bus */
+ if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+ if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* SCSI bus */
max_channel++;
}
if (!max_channel) {
- printk(KERN_WARNING "scsi-osm: no channels found on %s\n",
- c->name);
+ osm_warn("no channels found on %s\n", c->name);
return ERR_PTR(-EFAULT);
}
scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
if (!scsi_host) {
- printk(KERN_WARNING "scsi-osm: Could not allocate SCSI host\n");
+ osm_warn("Could not allocate SCSI host\n");
return ERR_PTR(-ENOMEM);
}
scsi_host->max_id = i2o_scsi_max_id;
scsi_host->max_lun = i2o_scsi_max_lun;
scsi_host->this_id = c->unit;
-
- sb = c->status_block.virt;
-
- scsi_host->sg_tablesize = (sb->inbound_frame_size -
- sizeof(struct i2o_message) / 4 - 6) / 2;
+ scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
i2o_shost->scsi_host = scsi_host;
i2o_shost->iop = c;
+ i2o_shost->lun = 1;
i = 0;
list_for_each_entry(i2o_dev, &c->devices, list)
- if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
- if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* only SCSI bus */
+ if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+ if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* only SCSI bus */
i2o_shost->channel[i++] = i2o_dev;
if (i >= max_channel)
struct i2o_scsi_host *i2o_shost;
struct scsi_device *scsi_dev;
+ osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
i2o_shost = i2o_scsi_get_host(c);
shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
if (scsi_dev->hostdata == i2o_dev) {
+ sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
scsi_remove_device(scsi_dev);
scsi_device_put(scsi_dev);
break;
struct Scsi_Host *scsi_host;
struct i2o_device *parent;
struct scsi_device *scsi_dev;
- u32 id;
- u64 lun;
+ u32 id = -1;
+ u64 lun = -1;
int channel = -1;
int i;
scsi_host = i2o_shost->scsi_host;
- if (i2o_parm_field_get(i2o_dev, 0, 3, &id, 4) < 0)
- return -EFAULT;
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ case I2O_CLASS_EXECUTIVE:
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u8 type;
+ struct i2o_device *d = i2o_shost->channel[0];
+
+ if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* SCSI bus */
+ if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
+ channel = 0;
+ if (i2o_dev->lct_data.class_id ==
+ I2O_CLASS_RANDOM_BLOCK_STORAGE)
+ lun =
+ cpu_to_le64(i2o_shost->
+ lun++);
+ else
+ lun = 0;
+ }
+ }
+#endif
+ break;
- if (id >= scsi_host->max_id) {
- printk(KERN_WARNING "scsi-osm: SCSI device id (%d) >= max_id "
- "of I2O host (%d)", id, scsi_host->max_id);
+ case I2O_CLASS_SCSI_PERIPHERAL:
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4))
+ return -EFAULT;
+
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8))
+ return -EFAULT;
+
+ parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
+ if (!parent) {
+ osm_warn("can not find parent of device %03x\n",
+ i2o_dev->lct_data.tid);
+ return -EFAULT;
+ }
+
+ for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
+ if (i2o_shost->channel[i] == parent)
+ channel = i;
+ break;
+
+ default:
return -EFAULT;
}
- if (i2o_parm_field_get(i2o_dev, 0, 4, &lun, 8) < 0)
- return -EFAULT;
- if (lun >= scsi_host->max_lun) {
- printk(KERN_WARNING "scsi-osm: SCSI device id (%d) >= max_lun "
- "of I2O host (%d)", (unsigned int)lun,
- scsi_host->max_lun);
+ if (channel == -1) {
+ osm_warn("can not find channel of device %03x\n",
+ i2o_dev->lct_data.tid);
return -EFAULT;
}
- parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
- if (!parent) {
- printk(KERN_WARNING "scsi-osm: can not find parent of device "
- "%03x\n", i2o_dev->lct_data.tid);
+ if (le32_to_cpu(id) >= scsi_host->max_id) {
+ osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)",
+ le32_to_cpu(id), scsi_host->max_id);
return -EFAULT;
}
- for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
- if (i2o_shost->channel[i] == parent)
- channel = i;
-
- if (channel == -1) {
- printk(KERN_WARNING "scsi-osm: can not find channel of device "
- "%03x\n", i2o_dev->lct_data.tid);
+ if (le64_to_cpu(lun) >= scsi_host->max_lun) {
+ osm_warn("SCSI device lun (%lu) >= max_lun of I2O host (%d)",
+ (long unsigned int)le64_to_cpu(lun),
+ scsi_host->max_lun);
return -EFAULT;
}
scsi_dev =
- __scsi_add_device(i2o_shost->scsi_host, channel, id, lun, i2o_dev);
+ __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id),
+ le64_to_cpu(lun), i2o_dev);
- if (!scsi_dev) {
- printk(KERN_WARNING "scsi-osm: can not add SCSI device "
- "%03x\n", i2o_dev->lct_data.tid);
- return -EFAULT;
+ if (IS_ERR(scsi_dev)) {
+ osm_warn("can not add SCSI device %03x\n",
+ i2o_dev->lct_data.tid);
+ return PTR_ERR(scsi_dev);
}
- pr_debug("Added new SCSI device %03x (cannel: %d, id: %d, lun: %d)\n",
- i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
+ sysfs_create_link(&i2o_dev->device.kobj, &scsi_dev->sdev_gendev.kobj,
+ "scsi");
+
+ osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %ld\n",
+ i2o_dev->lct_data.tid, channel, le32_to_cpu(id),
+ (long unsigned int)le64_to_cpu(lun));
return 0;
};
return hostdata->iop->name;
}
-#if 0
-/**
- * i2o_retry_run - retry on timeout
- * @f: unused
- *
- * Retry congested frames. This actually needs pushing down into
- * i2o core. We should only bother the OSM with this when we can't
- * queue and retry the frame. Or perhaps we should call the OSM
- * and its default handler should be this in the core, and this
- * call a 2nd "I give up" handler in the OSM ?
- */
-
-static void i2o_retry_run(unsigned long f)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&retry_lock, flags);
- for (i = 0; i < retry_ct; i++)
- i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
- retry_ct = 0;
- spin_unlock_irqrestore(&retry_lock, flags);
-}
-
-/**
- * flush_pending - empty the retry queue
- *
- * Turn each of the pending commands into a NOP and post it back
- * to the controller to clear it.
- */
-
-static void flush_pending(void)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&retry_lock, flags);
- for (i = 0; i < retry_ct; i++) {
- retry[i][0] &= ~0xFFFFFF;
- retry[i][0] |= I2O_CMD_UTIL_NOP << 24;
- i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
- }
- retry_ct = 0;
- spin_unlock_irqrestore(&retry_lock, flags);
-}
-#endif
-
/**
* i2o_scsi_reply - SCSI OSM message reply handler
* @c: controller issuing the reply
struct i2o_message *msg)
{
struct scsi_cmnd *cmd;
+ u32 error;
struct device *dev;
- u8 as, ds, st;
-
- cmd = i2o_cntxt_list_get(c, readl(&msg->u.s.tcntxt));
-
- if (msg->u.head[0] & (1 << 13)) {
- struct i2o_message *pmsg; /* preserved message */
- u32 pm;
- pm = readl(&msg->body[3]);
-
- pmsg = c->in_queue.virt + pm;
-
- printk("IOP fail.\n");
- printk("From %d To %d Cmd %d.\n",
- (msg->u.head[1] >> 12) & 0xFFF,
- msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24);
- printk("Failure Code %d.\n", msg->body[0] >> 24);
- if (msg->body[0] & (1 << 16))
- printk("Format error.\n");
- if (msg->body[0] & (1 << 17))
- printk("Path error.\n");
- if (msg->body[0] & (1 << 18))
- printk("Path State.\n");
- if (msg->body[0] & (1 << 18))
- printk("Congestion.\n");
-
- printk("Failing message is %p.\n", pmsg);
-
- cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt));
- if (!cmd)
- return 1;
-
- printk("Aborted %ld\n", cmd->serial_number);
- cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
-
- /* Now flush the message by making it a NOP */
- i2o_msg_nop(c, pm);
-
- return 1;
+ cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
+ if (unlikely(!cmd)) {
+ osm_err("NULL reply received!\n");
+ return -1;
}
/*
* Low byte is device status, next is adapter status,
* (then one byte reserved), then request status.
*/
- ds = (u8) readl(&msg->body[0]);
- as = (u8) (readl(&msg->body[0]) >> 8);
- st = (u8) (readl(&msg->body[0]) >> 24);
+ error = le32_to_cpu(msg->body[0]);
+ osm_debug("Completed %ld\n", cmd->serial_number);
+
+ cmd->result = error & 0xff;
/*
- * Is this a control request coming back - eg an abort ?
+ * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
+ * the SCSI layer handle the error
*/
+ if (cmd->result)
+ memcpy(cmd->sense_buffer, &msg->body[3],
+ min(sizeof(cmd->sense_buffer), (size_t) 40));
- if (!cmd) {
- if (st)
- printk(KERN_WARNING "SCSI abort: %08X",
- readl(&msg->body[0]));
- printk(KERN_INFO "SCSI abort completed.\n");
- return -EFAULT;
- }
-
- pr_debug("Completed %ld\n", cmd->serial_number);
-
- if (st) {
- u32 count, error;
- /* An error has occurred */
-
- switch (st) {
- case 0x06:
- count = readl(&msg->body[1]);
- if (count < cmd->underflow) {
- int i;
- printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X"
- "\n", count, cmd->underflow);
- printk("Cmd: ");
- for (i = 0; i < 15; i++)
- printk("%02X ", cmd->cmnd[i]);
- printk(".\n");
- cmd->result = (DID_ERROR << 16);
- }
- break;
+ /* only output error code if AdapterStatus is not HBA_SUCCESS */
+ if ((error >> 8) & 0xff)
+ osm_err("SCSI error %08x\n", error);
- default:
- error = readl(&msg->body[0]);
-
- printk(KERN_ERR "scsi-osm: SCSI error %08x\n", error);
-
- if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) {
- int i;
- u32 len = sizeof(cmd->sense_buffer);
- len = (len > 40) ? 40 : len;
- // Copy over the sense data
- memcpy(cmd->sense_buffer, (void *)&msg->body[3],
- len);
- for (i = 0; i <= len; i++)
- printk(KERN_INFO "%02x\n",
- cmd->sense_buffer[i]);
- if (cmd->sense_buffer[0] == 0x70
- && cmd->sense_buffer[2] == DATA_PROTECT) {
- /* This is to handle an array failed */
- cmd->result = (DID_TIME_OUT << 16);
- printk(KERN_WARNING "%s: SCSI Data "
- "Protect-Device (%d,%d,%d) "
- "hba_status=0x%x, dev_status="
- "0x%x, cmd=0x%x\n", c->name,
- (u32) cmd->device->channel,
- (u32) cmd->device->id,
- (u32) cmd->device->lun,
- (error >> 8) & 0xff,
- error & 0xff, cmd->cmnd[0]);
- } else
- cmd->result = (DID_ERROR << 16);
-
- break;
- }
-
- switch (as) {
- case 0x0E:
- /* SCSI Reset */
- cmd->result = DID_RESET << 16;
- break;
-
- case 0x0F:
- cmd->result = DID_PARITY << 16;
- break;
-
- default:
- cmd->result = DID_ERROR << 16;
- break;
- }
+ dev = &c->pdev->dev;
+ if (cmd->use_sg)
+ dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
+ cmd->sc_data_direction);
+ else if (cmd->SCp.dma_handle)
+ dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen,
+ cmd->sc_data_direction);
- break;
- }
+ cmd->scsi_done(cmd);
- cmd->scsi_done(cmd);
- return 1;
- }
+ return 1;
+};
- cmd->result = DID_OK << 16 | ds;
+/**
+ * i2o_scsi_notify_device_add - Retrieve notifications of added devices
+ * @i2o_dev: the I2O device which was added
+ *
+ * If a I2O device is added we catch the notification, because I2O classes
+ * other then SCSI peripheral will not be received through
+ * i2o_scsi_probe().
+ */
+static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_probe(&i2o_dev->device);
+ break;
- cmd->scsi_done(cmd);
+ default:
+ break;
+ }
+};
- dev = &c->pdev->dev;
- if (cmd->use_sg)
- dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer,
- cmd->use_sg, cmd->sc_data_direction);
- else if (cmd->request_bufflen)
- dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr),
- cmd->request_bufflen, cmd->sc_data_direction);
+/**
+ * i2o_scsi_notify_device_remove - Retrieve notifications of removed
+ * devices
+ * @i2o_dev: the I2O device which was removed
+ *
+ * If a I2O device is removed, we catch the notification to remove the
+ * corresponding SCSI device.
+ */
+static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_remove(&i2o_dev->device);
+ break;
- return 1;
+ default:
+ break;
+ }
};
/**
* If a I2O controller is added, we catch the notification to add a
* corresponding Scsi_Host.
*/
-void i2o_scsi_notify_controller_add(struct i2o_controller *c)
+static void i2o_scsi_notify_controller_add(struct i2o_controller *c)
{
struct i2o_scsi_host *i2o_shost;
int rc;
i2o_shost = i2o_scsi_host_alloc(c);
if (IS_ERR(i2o_shost)) {
- printk(KERN_ERR "scsi-osm: Could not initialize"
- " SCSI host\n");
+ osm_err("Could not initialize SCSI host\n");
return;
}
rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
if (rc) {
- printk(KERN_ERR "scsi-osm: Could not add SCSI "
- "host\n");
+ osm_err("Could not add SCSI host\n");
scsi_host_put(i2o_shost->scsi_host);
return;
}
c->driver_data[i2o_scsi_driver.context] = i2o_shost;
- pr_debug("new I2O SCSI host added\n");
+ osm_debug("new I2O SCSI host added\n");
};
/**
* If a I2O controller is removed, we catch the notification to remove the
* corresponding Scsi_Host.
*/
-void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
+static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
{
struct i2o_scsi_host *i2o_shost;
i2o_shost = i2o_scsi_get_host(c);
scsi_remove_host(i2o_shost->scsi_host);
scsi_host_put(i2o_shost->scsi_host);
- pr_debug("I2O SCSI host removed\n");
+ osm_debug("I2O SCSI host removed\n");
};
/* SCSI OSM driver struct */
static struct i2o_driver i2o_scsi_driver = {
- .name = "scsi-osm",
+ .name = OSM_NAME,
.reply = i2o_scsi_reply,
.classes = i2o_scsi_class_id,
+ .notify_device_add = i2o_scsi_notify_device_add,
+ .notify_device_remove = i2o_scsi_notify_device_remove,
.notify_controller_add = i2o_scsi_notify_controller_add,
.notify_controller_remove = i2o_scsi_notify_controller_remove,
.driver = {
void (*done) (struct scsi_cmnd *))
{
struct i2o_controller *c;
- struct Scsi_Host *host;
struct i2o_device *i2o_dev;
- struct device *dev;
int tid;
struct i2o_message *msg;
- u32 m;
- u32 scsi_flags, sg_flags;
- u32 *mptr, *lenptr;
- u32 len, reqlen;
- int i;
+ /*
+ * ENABLE_DISCONNECT
+ * SIMPLE_TAG
+ * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+ */
+ u32 scsi_flags = 0x20a00000;
+ u32 sgl_offset;
+ u32 *mptr;
+ u32 cmd = I2O_CMD_SCSI_EXEC << 24;
+ int rc = 0;
/*
* Do the incoming paperwork
*/
-
i2o_dev = SCpnt->device->hostdata;
- host = SCpnt->device->host;
c = i2o_dev->iop;
- dev = &c->pdev->dev;
SCpnt->scsi_done = done;
if (unlikely(!i2o_dev)) {
- printk(KERN_WARNING "scsi-osm: no I2O device in request\n");
+ osm_warn("no I2O device in request\n");
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
- return 0;
+ goto exit;
}
tid = i2o_dev->lct_data.tid;
- pr_debug("qcmd: Tid = %03x\n", tid);
- pr_debug("Real scsi messages.\n");
-
- /*
- * Obtain an I2O message. If there are none free then
- * throw it back to the scsi layer
- */
-
- m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
- if (m == I2O_QUEUE_EMPTY)
- return SCSI_MLQUEUE_HOST_BUSY;
+ osm_debug("qcmd: Tid = %03x\n", tid);
+ osm_debug("Real scsi messages.\n");
/*
* Put together a scsi execscb message
*/
-
- len = SCpnt->request_bufflen;
-
switch (SCpnt->sc_data_direction) {
case PCI_DMA_NONE:
- scsi_flags = 0x00000000; // DATA NO XFER
- sg_flags = 0x00000000;
+ /* DATA NO XFER */
+ sgl_offset = SGL_OFFSET_0;
break;
case PCI_DMA_TODEVICE:
- scsi_flags = 0x80000000; // DATA OUT (iop-->dev)
- sg_flags = 0x14000000;
+ /* DATA OUT (iop-->dev) */
+ scsi_flags |= 0x80000000;
+ sgl_offset = SGL_OFFSET_10;
break;
case PCI_DMA_FROMDEVICE:
- scsi_flags = 0x40000000; // DATA IN (iop<--dev)
- sg_flags = 0x10000000;
+ /* DATA IN (iop<--dev) */
+ scsi_flags |= 0x40000000;
+ sgl_offset = SGL_OFFSET_10;
break;
default:
/* Unknown - kill the command */
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
- return 0;
+ goto exit;
+ }
+
+ /*
+ * Obtain an I2O message. If there are none free then
+ * throw it back to the scsi layer
+ */
+
+ msg = i2o_msg_get(c);
+ if (IS_ERR(msg)) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto exit;
+ }
+
+ mptr = &msg->body[0];
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u32 adpt_flags = 0;
+
+ if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
+ i2o_sg_io_hdr_t __user *usr_ptr =
+ ((Sg_request *) (SCpnt->sc_request->
+ upper_private_data))->header.
+ usr_ptr;
+
+ if (usr_ptr)
+ get_user(adpt_flags, &usr_ptr->flags);
+ }
+
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ /* interpret flag has to be set for executive */
+ adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * for Adaptec controllers we use the PRIVATE command, because
+ * the normal SCSI EXEC doesn't support all SCSI commands on
+ * all controllers (for example READ CAPACITY).
+ */
+ if (sgl_offset == SGL_OFFSET_10)
+ sgl_offset = SGL_OFFSET_12;
+ cmd = I2O_CMD_PRIVATE << 24;
+ *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
+ *mptr++ = cpu_to_le32(adpt_flags | tid);
}
+#endif
- writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[1]);
- writel(i2o_scsi_driver.context, &msg->u.s.icntxt);
+ msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
+ msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context);
/* We want the SCSI control block back */
- writel(i2o_cntxt_list_add(c, SCpnt), &msg->u.s.tcntxt);
+ msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt));
/* LSI_920_PCI_QUIRK
*
*/
/* Attach tags to the devices */
- /*
+ /* FIXME: implement
if(SCpnt->device->tagged_supported) {
if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
scsi_flags |= 0x01000000;
}
*/
- /* Direction, disconnect ok, tag, CDBLen */
- writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]);
-
- mptr = &msg->body[1];
+ *mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len);
/* Write SCSI command into the message - always 16 byte block */
- memcpy_toio(mptr, SCpnt->cmnd, 16);
+ memcpy(mptr, SCpnt->cmnd, 16);
mptr += 4;
- lenptr = mptr++; /* Remember me - fill in when we know */
-
- reqlen = 12; // SINGLE SGE
-
- /* Now fill in the SGList and command */
- if (SCpnt->use_sg) {
- struct scatterlist *sg;
- int sg_count;
-
- sg = SCpnt->request_buffer;
- len = 0;
-
- sg_count = dma_map_sg(dev, sg, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- if (unlikely(sg_count <= 0))
- return -ENOMEM;
-
- for (i = SCpnt->use_sg; i > 0; i--) {
- if (i == 1)
- sg_flags |= 0xC0000000;
- writel(sg_flags | sg_dma_len(sg), mptr++);
- writel(sg_dma_address(sg), mptr++);
- len += sg_dma_len(sg);
- sg++;
+ if (sgl_offset != SGL_OFFSET_0) {
+ /* write size of data addressed by SGL */
+ *mptr++ = cpu_to_le32(SCpnt->request_bufflen);
+
+ /* Now fill in the SGList and command */
+ if (SCpnt->use_sg) {
+ if (!i2o_dma_map_sg(c, SCpnt->request_buffer,
+ SCpnt->use_sg,
+ SCpnt->sc_data_direction, &mptr))
+ goto nomem;
+ } else {
+ SCpnt->SCp.dma_handle =
+ i2o_dma_map_single(c, SCpnt->request_buffer,
+ SCpnt->request_bufflen,
+ SCpnt->sc_data_direction, &mptr);
+ if (dma_mapping_error(SCpnt->SCp.dma_handle))
+ goto nomem;
}
-
- reqlen = mptr - &msg->u.head[0];
- writel(len, lenptr);
- } else {
- len = SCpnt->request_bufflen;
-
- writel(len, lenptr);
-
- if (len > 0) {
- dma_addr_t dma_addr;
-
- dma_addr = dma_map_single(dev, SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- if (!dma_addr)
- return -ENOMEM;
-
- SCpnt->SCp.ptr = (void *)(unsigned long)dma_addr;
- sg_flags |= 0xC0000000;
- writel(sg_flags | SCpnt->request_bufflen, mptr++);
- writel(dma_addr, mptr++);
- } else
- reqlen = 9;
}
/* Stick the headers on */
- writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]);
+ msg->u.head[0] =
+ cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
/* Queue the message */
- i2o_msg_post(c, m);
+ i2o_msg_post(c, msg);
- pr_debug("Issued %ld\n", SCpnt->serial_number);
+ osm_debug("Issued %ld\n", SCpnt->serial_number);
return 0;
+
+ nomem:
+ rc = -ENOMEM;
+ i2o_msg_nop(c, msg);
+
+ exit:
+ return rc;
};
/**
* Returns 0 if the command is successfully aborted or negative error code
* on failure.
*/
-int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
+static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
{
struct i2o_device *i2o_dev;
struct i2o_controller *c;
struct i2o_message *msg;
- u32 m;
int tid;
int status = FAILED;
- printk(KERN_WARNING "i2o_scsi: Aborting command block.\n");
+ osm_warn("Aborting command block.\n");
i2o_dev = SCpnt->device->hostdata;
c = i2o_dev->iop;
tid = i2o_dev->lct_data.tid;
- m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
- if (m == I2O_QUEUE_EMPTY)
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
return SCSI_MLQUEUE_HOST_BUSY;
- writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
- writel(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid,
- &msg->u.head[1]);
- writel(i2o_cntxt_list_get_ptr(c, SCpnt), &msg->body[0]);
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
+ msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
- if (i2o_msg_post_wait(c, m, I2O_TIMEOUT_SCSI_SCB_ABORT))
+ if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
status = SUCCESS;
return status;
}
static struct scsi_host_template i2o_scsi_host_template = {
- .proc_name = "SCSI-OSM",
- .name = "I2O SCSI Peripheral OSM",
+ .proc_name = OSM_NAME,
+ .name = OSM_DESCRIPTION,
.info = i2o_scsi_info,
.queuecommand = i2o_scsi_queuecommand,
.eh_abort_handler = i2o_scsi_abort,
.use_clustering = ENABLE_CLUSTERING,
};
-/*
-int
-i2o_scsi_queuecommand(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
-{
- printk(KERN_INFO "queuecommand\n");
- return SCSI_MLQUEUE_HOST_BUSY;
-};
-*/
-
/**
* i2o_scsi_init - SCSI OSM initialization function
*
{
int rc;
- printk(KERN_INFO "I2O SCSI Peripheral OSM\n");
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
/* Register SCSI OSM into I2O core */
rc = i2o_driver_register(&i2o_scsi_driver);
if (rc) {
- printk(KERN_ERR "scsi-osm: Could not register SCSI driver\n");
+ osm_err("Could not register SCSI driver\n");
return rc;
}
MODULE_AUTHOR("Red Hat Software");
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
module_init(i2o_scsi_init);
module_exit(i2o_scsi_exit);