* - retry arbitration if lost (unless higher levels do this for us)
* - power down the chip when no device is detected
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
MODULE_DESCRIPTION("PowerMac MESH SCSI driver");
MODULE_LICENSE("GPL");
-MODULE_PARM(sync_rate, "i");
-MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
-MODULE_PARM(sync_targets, "i");
-MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
-MODULE_PARM(resel_targets, "i");
-MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
-MODULE_PARM(debug_targets, "i");
-MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
-MODULE_PARM(init_reset_delay, "i");
-MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
-
static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE;
static int sync_targets = 0xff;
static int resel_targets = 0xff;
static int debug_targets = 0; /* print debug for these targets */
static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS;
+module_param(sync_rate, int, 0);
+MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
+module_param(sync_targets, int, 0);
+MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
+module_param(resel_targets, int, 0);
+MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
+module_param(debug_targets, int, 0644);
+MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
+module_param(init_reset_delay, int, 0);
+MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
+
static int mesh_sync_period = 100;
static int mesh_sync_offset = 0;
static unsigned char use_active_neg = 0; /* bit mask for SEQ_ACTIVE_NEG if used */
};
struct mesh_state {
- volatile struct mesh_regs *mesh;
+ volatile struct mesh_regs __iomem *mesh;
int meshintr;
- volatile struct dbdma_regs *dma;
+ volatile struct dbdma_regs __iomem *dma;
int dmaintr;
struct Scsi_Host *host;
struct mesh_state *next;
* Driver is too messy, we need a few prototypes...
*/
static void mesh_done(struct mesh_state *ms, int start_next);
-static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
+static void mesh_interrupt(int irq, void *dev_id);
static void cmd_complete(struct mesh_state *ms);
static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
static void halt_dma(struct mesh_state *ms);
static void
mesh_dump_regs(struct mesh_state *ms)
{
- volatile struct mesh_regs *mr = ms->mesh;
- volatile struct dbdma_regs *md = ms->dma;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
+ volatile struct dbdma_regs __iomem *md = ms->dma;
int t;
struct mesh_target *tp;
/*
* Flush write buffers on the bus path to the mesh
*/
-static inline void mesh_flush_io(volatile struct mesh_regs *mr)
+static inline void mesh_flush_io(volatile struct mesh_regs __iomem *mr)
{
(void)in_8(&mr->mesh_id);
}
*/
static void mesh_init(struct mesh_state *ms)
{
- volatile struct mesh_regs *mr = ms->mesh;
- volatile struct dbdma_regs *md = ms->dma;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
+ volatile struct dbdma_regs __iomem *md = ms->dma;
mesh_flush_io(mr);
udelay(100);
mesh_flush_io(mr);
/* Wait for bus to come back */
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout((init_reset_delay * HZ) / 1000);
+ msleep(init_reset_delay);
}
/* Reconfigure controller */
static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
{
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
int t, id;
id = cmd->device->id;
dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
MKWORD(mr->interrupt, mr->exception,
mr->error, mr->fifo_count));
- mesh_interrupt(0, (void *)ms, 0);
+ mesh_interrupt(0, (void *)ms);
if (ms->phase != arbitrating)
return;
}
dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
MKWORD(mr->interrupt, mr->exception,
mr->error, mr->fifo_count));
- mesh_interrupt(0, (void *)ms, 0);
+ mesh_interrupt(0, (void *)ms);
if (ms->phase != arbitrating)
return;
dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
cmd = ms->current_req;
- ms->current_req = 0;
- tp->current_req = 0;
+ ms->current_req = NULL;
+ tp->current_req = NULL;
if (cmd) {
cmd->result = (ms->stat << 16) + cmd->SCp.Status;
if (ms->stat == DID_OK)
static void set_sdtr(struct mesh_state *ms, int period, int offset)
{
struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
int v, tr;
tp->sdtr_state = sdtr_done;
static void start_phase(struct mesh_state *ms)
{
int i, seq, nb;
- volatile struct mesh_regs *mr = ms->mesh;
- volatile struct dbdma_regs *md = ms->dma;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
+ volatile struct dbdma_regs __iomem *md = ms->dma;
struct scsi_cmnd *cmd = ms->current_req;
struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
* issue a SEQ_MSGOUT to get the mesh to drop ACK.
*/
if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) {
- dlog(ms, "bus0 was %.2x explictly asserting ATN", mr->bus_status0);
+ dlog(ms, "bus0 was %.2x explicitly asserting ATN", mr->bus_status0);
out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */
mesh_flush_io(mr);
udelay(1);
static inline void get_msgin(struct mesh_state *ms)
{
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
int i, n;
n = mr->fifo_count;
static void reselected(struct mesh_state *ms)
{
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
struct scsi_cmnd *cmd;
struct mesh_target *tp;
int b, t, prev;
int tgt;
struct mesh_target *tp;
struct scsi_cmnd *cmd;
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
for (tgt = 0; tgt < 8; ++tgt) {
tp = &ms->tgts[tgt];
out_8(&mr->sequence, SEQ_ENBRESEL);
}
-static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
spin_lock_irqsave(dev->host_lock, flags);
- mesh_interrupt(irq, dev_id, ptregs);
+ mesh_interrupt(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
static void handle_error(struct mesh_state *ms)
{
int err, exc, count;
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
err = in_8(&mr->error);
exc = in_8(&mr->exception);
static void handle_exception(struct mesh_state *ms)
{
int exc;
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
exc = in_8(&mr->exception);
out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
} else if (code != cmd->device->lun + IDENTIFY_BASE) {
printk(KERN_WARNING "mesh: lun mismatch "
"(%d != %d) on reselection from "
- "target %d\n", i, cmd->device->lun,
- ms->conn_tgt);
+ "target %d\n", code - IDENTIFY_BASE,
+ cmd->device->lun, ms->conn_tgt);
}
break;
}
if (cmd->use_sg > 0) {
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
off = ms->data_ptr;
nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
static void halt_dma(struct mesh_state *ms)
{
- volatile struct dbdma_regs *md = ms->dma;
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct dbdma_regs __iomem *md = ms->dma;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
struct scsi_cmnd *cmd = ms->current_req;
int t, nb;
static void phase_mismatch(struct mesh_state *ms)
{
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
int phase;
dlog(ms, "phasemm ch/cl/seq/fc=%.8x",
static void cmd_complete(struct mesh_state *ms)
{
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
struct scsi_cmnd *cmd = ms->current_req;
struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
int seq, n, t;
mesh_done(ms, 1);
return;
case disconnecting:
- ms->current_req = 0;
+ ms->current_req = NULL;
ms->phase = idle;
mesh_start(ms);
return;
* handler (do_mesh_interrupt) or by other functions in
* exceptional circumstances
*/
-static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static void mesh_interrupt(int irq, void *dev_id)
{
struct mesh_state *ms = (struct mesh_state *) dev_id;
- volatile struct mesh_regs *mr = ms->mesh;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
int intr;
#if 0
static int mesh_host_reset(struct scsi_cmnd *cmd)
{
struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
- volatile struct mesh_regs *mr = ms->mesh;
- volatile struct dbdma_regs *md = ms->dma;
+ volatile struct mesh_regs __iomem *mr = ms->mesh;
+ volatile struct dbdma_regs __iomem *md = ms->dma;
+ unsigned long flags;
printk(KERN_DEBUG "mesh_host_reset\n");
+ spin_lock_irqsave(ms->host->host_lock, flags);
+
/* Reset the controller & dbdma channel */
out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */
out_8(&mr->exception, 0xff); /* clear all exception bits */
/* Complete pending commands */
handle_reset(ms);
+ spin_unlock_irqrestore(ms->host->host_lock, flags);
return SUCCESS;
}
static void set_mesh_power(struct mesh_state *ms, int state)
{
- if (_machine != _MACH_Pmac)
+ if (!machine_is(powermac))
return;
if (state) {
pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/5);
+ msleep(200);
} else {
pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/100);
+ msleep(10);
}
-}
+}
#ifdef CONFIG_PM
-static int mesh_suspend(struct macio_dev *mdev, u32 state)
+static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg)
{
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
unsigned long flags;
- if (state == mdev->ofdev.dev.power_state || state < 2)
+ switch (mesg.event) {
+ case PM_EVENT_SUSPEND:
+ case PM_EVENT_FREEZE:
+ break;
+ default:
+ return 0;
+ }
+ if (mesg.event == mdev->ofdev.dev.power.power_state.event)
return 0;
scsi_block_requests(ms->host);
spin_lock_irqsave(ms->host->host_lock, flags);
while(ms->phase != idle) {
spin_unlock_irqrestore(ms->host->host_lock, flags);
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(HZ/100);
+ msleep(10);
spin_lock_irqsave(ms->host->host_lock, flags);
}
ms->phase = sleeping;
disable_irq(ms->meshintr);
set_mesh_power(ms, 0);
- mdev->ofdev.dev.power_state = state;
+ mdev->ofdev.dev.power.power_state = mesg;
return 0;
}
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
unsigned long flags;
- if (mdev->ofdev.dev.power_state == 0)
+ if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
return 0;
set_mesh_power(ms, 1);
enable_irq(ms->meshintr);
scsi_unblock_requests(ms->host);
- mdev->ofdev.dev.power_state = 0;
+ mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;
return 0;
}
static int mesh_shutdown(struct macio_dev *mdev)
{
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
- volatile struct mesh_regs *mr;
+ volatile struct mesh_regs __iomem *mr;
unsigned long flags;
printk(KERN_INFO "resetting MESH scsi bus(es)\n");
.use_clustering = DISABLE_CLUSTERING,
};
-static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
+static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mesh = macio_get_of_node(mdev);
struct pci_dev* pdev = macio_get_pci_dev(mdev);
- int tgt, *cfp, minper;
+ int tgt, minper;
+ const int *cfp;
struct mesh_state *ms;
struct Scsi_Host *mesh_host;
void *dma_cmd_space;
if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
- " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+ " (got %d,%d)\n", macio_resource_count(mdev),
+ macio_irq_count(mdev));
return -ENODEV;
}
ms->mdev = mdev;
ms->pdev = pdev;
- ms->mesh = (volatile struct mesh_regs *)
- ioremap(macio_resource_start(mdev, 0), 0x1000);
+ ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000);
if (ms->mesh == NULL) {
printk(KERN_ERR "mesh: can't map registers\n");
goto out_free;
}
- ms->dma = (volatile struct dbdma_regs *)
- ioremap(macio_resource_start(mdev, 1), 0x1000);
+ ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000);
if (ms->dma == NULL) {
printk(KERN_ERR "mesh: can't map registers\n");
- iounmap((void *)ms->mesh);
+ iounmap(ms->mesh);
goto out_free;
}
for (tgt = 0; tgt < 8; ++tgt) {
ms->tgts[tgt].sdtr_state = do_sdtr;
ms->tgts[tgt].sync_params = ASYNC_PARAMS;
- ms->tgts[tgt].current_req = 0;
+ ms->tgts[tgt].current_req = NULL;
}
- if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
+ if ((cfp = get_property(mesh, "clock-frequency", NULL)))
ms->clk_freq = *cfp;
else {
printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
/* Set it up */
mesh_init(ms);
- /* XXX FIXME: error should be fatal */
- if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms))
+ /* Request interrupt */
+ if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+ goto out_shutdown;
+ }
- /* XXX FIXME: handle failure */
- scsi_add_host(mesh_host, &mdev->ofdev.dev);
+ /* Add scsi host & scan */
+ if (scsi_add_host(mesh_host, &mdev->ofdev.dev))
+ goto out_release_irq;
scsi_scan_host(mesh_host);
return 0;
-out_unmap:
- iounmap((void *)ms->dma);
- iounmap((void *)ms->mesh);
-out_free:
+ out_release_irq:
+ free_irq(ms->meshintr, ms);
+ out_shutdown:
+ /* shutdown & reset bus in case of error or macos can be confused
+ * at reboot if the bus was set to synchronous mode already
+ */
+ mesh_shutdown(mdev);
+ set_mesh_power(ms, 0);
+ pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
+ ms->dma_cmd_space, ms->dma_cmd_bus);
+ out_unmap:
+ iounmap(ms->dma);
+ iounmap(ms->mesh);
+ out_free:
scsi_host_put(mesh_host);
-out_release:
+ out_release:
macio_release_resources(mdev);
return -ENODEV;
set_mesh_power(ms, 0);
/* Unmap registers & dma controller */
- iounmap((void *) ms->mesh);
- iounmap((void *) ms->dma);
+ iounmap(ms->mesh);
+ iounmap(ms->dma);
/* Free DMA commands memory */
pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
- ms->dma_cmd_space, ms->dma_cmd_bus);
+ ms->dma_cmd_space, ms->dma_cmd_bus);
/* Release memory resources */
macio_release_resources(mdev);
}
-static struct of_match mesh_match[] =
+static struct of_device_id mesh_match[] =
{
{
.name = "mesh",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{
- .name = OF_ANY_MATCH,
.type = "scsi",
.compatible = "chrp,mesh0"
},
{},
};
+MODULE_DEVICE_TABLE (of, mesh_match);
static struct macio_driver mesh_driver =
{