xref: /openbmc/linux/drivers/scsi/myrb.c (revision 86aa961bb4619a68077ebeba21c52e9ba0eab43d)
1081ff398SHannes Reinecke // SPDX-License-Identifier: GPL-2.0
2081ff398SHannes Reinecke /*
3081ff398SHannes Reinecke  * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
4081ff398SHannes Reinecke  *
5081ff398SHannes Reinecke  * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
6081ff398SHannes Reinecke  *
7081ff398SHannes Reinecke  * Based on the original DAC960 driver,
8081ff398SHannes Reinecke  * Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
9081ff398SHannes Reinecke  * Portions Copyright 2002 by Mylex (An IBM Business Unit)
10081ff398SHannes Reinecke  *
11081ff398SHannes Reinecke  */
12081ff398SHannes Reinecke 
13081ff398SHannes Reinecke #include <linux/module.h>
14081ff398SHannes Reinecke #include <linux/types.h>
15081ff398SHannes Reinecke #include <linux/delay.h>
16081ff398SHannes Reinecke #include <linux/interrupt.h>
17081ff398SHannes Reinecke #include <linux/pci.h>
18081ff398SHannes Reinecke #include <linux/raid_class.h>
19081ff398SHannes Reinecke #include <asm/unaligned.h>
20081ff398SHannes Reinecke #include <scsi/scsi.h>
21081ff398SHannes Reinecke #include <scsi/scsi_host.h>
22081ff398SHannes Reinecke #include <scsi/scsi_device.h>
23081ff398SHannes Reinecke #include <scsi/scsi_cmnd.h>
24081ff398SHannes Reinecke #include <scsi/scsi_tcq.h>
25081ff398SHannes Reinecke #include "myrb.h"
26081ff398SHannes Reinecke 
27081ff398SHannes Reinecke static struct raid_template *myrb_raid_template;
28081ff398SHannes Reinecke 
29081ff398SHannes Reinecke static void myrb_monitor(struct work_struct *work);
30081ff398SHannes Reinecke static inline void myrb_translate_devstate(void *DeviceState);
31081ff398SHannes Reinecke 
myrb_logical_channel(struct Scsi_Host * shost)32081ff398SHannes Reinecke static inline int myrb_logical_channel(struct Scsi_Host *shost)
33081ff398SHannes Reinecke {
34081ff398SHannes Reinecke 	return shost->max_channel - 1;
35081ff398SHannes Reinecke }
36081ff398SHannes Reinecke 
37081ff398SHannes Reinecke static struct myrb_devstate_name_entry {
38081ff398SHannes Reinecke 	enum myrb_devstate state;
39081ff398SHannes Reinecke 	const char *name;
40081ff398SHannes Reinecke } myrb_devstate_name_list[] = {
41081ff398SHannes Reinecke 	{ MYRB_DEVICE_DEAD, "Dead" },
42081ff398SHannes Reinecke 	{ MYRB_DEVICE_WO, "WriteOnly" },
43081ff398SHannes Reinecke 	{ MYRB_DEVICE_ONLINE, "Online" },
44081ff398SHannes Reinecke 	{ MYRB_DEVICE_CRITICAL, "Critical" },
45081ff398SHannes Reinecke 	{ MYRB_DEVICE_STANDBY, "Standby" },
46081ff398SHannes Reinecke 	{ MYRB_DEVICE_OFFLINE, "Offline" },
47081ff398SHannes Reinecke };
48081ff398SHannes Reinecke 
myrb_devstate_name(enum myrb_devstate state)49081ff398SHannes Reinecke static const char *myrb_devstate_name(enum myrb_devstate state)
50081ff398SHannes Reinecke {
51081ff398SHannes Reinecke 	struct myrb_devstate_name_entry *entry = myrb_devstate_name_list;
52081ff398SHannes Reinecke 	int i;
53081ff398SHannes Reinecke 
54081ff398SHannes Reinecke 	for (i = 0; i < ARRAY_SIZE(myrb_devstate_name_list); i++) {
55081ff398SHannes Reinecke 		if (entry[i].state == state)
56081ff398SHannes Reinecke 			return entry[i].name;
57081ff398SHannes Reinecke 	}
58081ff398SHannes Reinecke 	return "Unknown";
59081ff398SHannes Reinecke }
60081ff398SHannes Reinecke 
61081ff398SHannes Reinecke static struct myrb_raidlevel_name_entry {
62081ff398SHannes Reinecke 	enum myrb_raidlevel level;
63081ff398SHannes Reinecke 	const char *name;
64081ff398SHannes Reinecke } myrb_raidlevel_name_list[] = {
65081ff398SHannes Reinecke 	{ MYRB_RAID_LEVEL0, "RAID0" },
66081ff398SHannes Reinecke 	{ MYRB_RAID_LEVEL1, "RAID1" },
67081ff398SHannes Reinecke 	{ MYRB_RAID_LEVEL3, "RAID3" },
68081ff398SHannes Reinecke 	{ MYRB_RAID_LEVEL5, "RAID5" },
69081ff398SHannes Reinecke 	{ MYRB_RAID_LEVEL6, "RAID6" },
70081ff398SHannes Reinecke 	{ MYRB_RAID_JBOD, "JBOD" },
71081ff398SHannes Reinecke };
72081ff398SHannes Reinecke 
myrb_raidlevel_name(enum myrb_raidlevel level)73081ff398SHannes Reinecke static const char *myrb_raidlevel_name(enum myrb_raidlevel level)
74081ff398SHannes Reinecke {
75081ff398SHannes Reinecke 	struct myrb_raidlevel_name_entry *entry = myrb_raidlevel_name_list;
76081ff398SHannes Reinecke 	int i;
77081ff398SHannes Reinecke 
78081ff398SHannes Reinecke 	for (i = 0; i < ARRAY_SIZE(myrb_raidlevel_name_list); i++) {
79081ff398SHannes Reinecke 		if (entry[i].level == level)
80081ff398SHannes Reinecke 			return entry[i].name;
81081ff398SHannes Reinecke 	}
82081ff398SHannes Reinecke 	return NULL;
83081ff398SHannes Reinecke }
84081ff398SHannes Reinecke 
8512a1b740SLee Jones /*
86081ff398SHannes Reinecke  * myrb_create_mempools - allocates auxiliary data structures
87081ff398SHannes Reinecke  *
88081ff398SHannes Reinecke  * Return: true on success, false otherwise.
89081ff398SHannes Reinecke  */
myrb_create_mempools(struct pci_dev * pdev,struct myrb_hba * cb)90081ff398SHannes Reinecke static bool myrb_create_mempools(struct pci_dev *pdev, struct myrb_hba *cb)
91081ff398SHannes Reinecke {
92081ff398SHannes Reinecke 	size_t elem_size, elem_align;
93081ff398SHannes Reinecke 
94081ff398SHannes Reinecke 	elem_align = sizeof(struct myrb_sge);
95081ff398SHannes Reinecke 	elem_size = cb->host->sg_tablesize * elem_align;
96081ff398SHannes Reinecke 	cb->sg_pool = dma_pool_create("myrb_sg", &pdev->dev,
97081ff398SHannes Reinecke 				      elem_size, elem_align, 0);
98081ff398SHannes Reinecke 	if (cb->sg_pool == NULL) {
99081ff398SHannes Reinecke 		shost_printk(KERN_ERR, cb->host,
100081ff398SHannes Reinecke 			     "Failed to allocate SG pool\n");
101081ff398SHannes Reinecke 		return false;
102081ff398SHannes Reinecke 	}
103081ff398SHannes Reinecke 
104081ff398SHannes Reinecke 	cb->dcdb_pool = dma_pool_create("myrb_dcdb", &pdev->dev,
105081ff398SHannes Reinecke 				       sizeof(struct myrb_dcdb),
106081ff398SHannes Reinecke 				       sizeof(unsigned int), 0);
107081ff398SHannes Reinecke 	if (!cb->dcdb_pool) {
108081ff398SHannes Reinecke 		dma_pool_destroy(cb->sg_pool);
109081ff398SHannes Reinecke 		cb->sg_pool = NULL;
110081ff398SHannes Reinecke 		shost_printk(KERN_ERR, cb->host,
111081ff398SHannes Reinecke 			     "Failed to allocate DCDB pool\n");
112081ff398SHannes Reinecke 		return false;
113081ff398SHannes Reinecke 	}
114081ff398SHannes Reinecke 
115081ff398SHannes Reinecke 	snprintf(cb->work_q_name, sizeof(cb->work_q_name),
116081ff398SHannes Reinecke 		 "myrb_wq_%d", cb->host->host_no);
117081ff398SHannes Reinecke 	cb->work_q = create_singlethread_workqueue(cb->work_q_name);
118081ff398SHannes Reinecke 	if (!cb->work_q) {
119081ff398SHannes Reinecke 		dma_pool_destroy(cb->dcdb_pool);
120081ff398SHannes Reinecke 		cb->dcdb_pool = NULL;
121081ff398SHannes Reinecke 		dma_pool_destroy(cb->sg_pool);
122081ff398SHannes Reinecke 		cb->sg_pool = NULL;
123081ff398SHannes Reinecke 		shost_printk(KERN_ERR, cb->host,
124081ff398SHannes Reinecke 			     "Failed to create workqueue\n");
125081ff398SHannes Reinecke 		return false;
126081ff398SHannes Reinecke 	}
127081ff398SHannes Reinecke 
128081ff398SHannes Reinecke 	/*
129081ff398SHannes Reinecke 	 * Initialize the Monitoring Timer.
130081ff398SHannes Reinecke 	 */
131081ff398SHannes Reinecke 	INIT_DELAYED_WORK(&cb->monitor_work, myrb_monitor);
132081ff398SHannes Reinecke 	queue_delayed_work(cb->work_q, &cb->monitor_work, 1);
133081ff398SHannes Reinecke 
134081ff398SHannes Reinecke 	return true;
135081ff398SHannes Reinecke }
136081ff398SHannes Reinecke 
13712a1b740SLee Jones /*
138081ff398SHannes Reinecke  * myrb_destroy_mempools - tears down the memory pools for the controller
139081ff398SHannes Reinecke  */
myrb_destroy_mempools(struct myrb_hba * cb)140081ff398SHannes Reinecke static void myrb_destroy_mempools(struct myrb_hba *cb)
141081ff398SHannes Reinecke {
142081ff398SHannes Reinecke 	cancel_delayed_work_sync(&cb->monitor_work);
143081ff398SHannes Reinecke 	destroy_workqueue(cb->work_q);
144081ff398SHannes Reinecke 
145081ff398SHannes Reinecke 	dma_pool_destroy(cb->sg_pool);
146081ff398SHannes Reinecke 	dma_pool_destroy(cb->dcdb_pool);
147081ff398SHannes Reinecke }
148081ff398SHannes Reinecke 
14912a1b740SLee Jones /*
150081ff398SHannes Reinecke  * myrb_reset_cmd - reset command block
151081ff398SHannes Reinecke  */
myrb_reset_cmd(struct myrb_cmdblk * cmd_blk)152081ff398SHannes Reinecke static inline void myrb_reset_cmd(struct myrb_cmdblk *cmd_blk)
153081ff398SHannes Reinecke {
154081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
155081ff398SHannes Reinecke 
156081ff398SHannes Reinecke 	memset(mbox, 0, sizeof(union myrb_cmd_mbox));
157081ff398SHannes Reinecke 	cmd_blk->status = 0;
158081ff398SHannes Reinecke }
159081ff398SHannes Reinecke 
16012a1b740SLee Jones /*
161081ff398SHannes Reinecke  * myrb_qcmd - queues command block for execution
162081ff398SHannes Reinecke  */
myrb_qcmd(struct myrb_hba * cb,struct myrb_cmdblk * cmd_blk)163081ff398SHannes Reinecke static void myrb_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
164081ff398SHannes Reinecke {
165081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
166081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
167081ff398SHannes Reinecke 	union myrb_cmd_mbox *next_mbox = cb->next_cmd_mbox;
168081ff398SHannes Reinecke 
169081ff398SHannes Reinecke 	cb->write_cmd_mbox(next_mbox, mbox);
170081ff398SHannes Reinecke 	if (cb->prev_cmd_mbox1->words[0] == 0 ||
171081ff398SHannes Reinecke 	    cb->prev_cmd_mbox2->words[0] == 0)
172081ff398SHannes Reinecke 		cb->get_cmd_mbox(base);
173081ff398SHannes Reinecke 	cb->prev_cmd_mbox2 = cb->prev_cmd_mbox1;
174081ff398SHannes Reinecke 	cb->prev_cmd_mbox1 = next_mbox;
175081ff398SHannes Reinecke 	if (++next_mbox > cb->last_cmd_mbox)
176081ff398SHannes Reinecke 		next_mbox = cb->first_cmd_mbox;
177081ff398SHannes Reinecke 	cb->next_cmd_mbox = next_mbox;
178081ff398SHannes Reinecke }
179081ff398SHannes Reinecke 
18012a1b740SLee Jones /*
181081ff398SHannes Reinecke  * myrb_exec_cmd - executes command block and waits for completion.
182081ff398SHannes Reinecke  *
183081ff398SHannes Reinecke  * Return: command status
184081ff398SHannes Reinecke  */
myrb_exec_cmd(struct myrb_hba * cb,struct myrb_cmdblk * cmd_blk)185081ff398SHannes Reinecke static unsigned short myrb_exec_cmd(struct myrb_hba *cb,
186081ff398SHannes Reinecke 		struct myrb_cmdblk *cmd_blk)
187081ff398SHannes Reinecke {
188081ff398SHannes Reinecke 	DECLARE_COMPLETION_ONSTACK(cmpl);
189081ff398SHannes Reinecke 	unsigned long flags;
190081ff398SHannes Reinecke 
191081ff398SHannes Reinecke 	cmd_blk->completion = &cmpl;
192081ff398SHannes Reinecke 
193081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
194081ff398SHannes Reinecke 	cb->qcmd(cb, cmd_blk);
195081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
196081ff398SHannes Reinecke 
197081ff398SHannes Reinecke 	wait_for_completion(&cmpl);
198081ff398SHannes Reinecke 	return cmd_blk->status;
199081ff398SHannes Reinecke }
200081ff398SHannes Reinecke 
20112a1b740SLee Jones /*
202081ff398SHannes Reinecke  * myrb_exec_type3 - executes a type 3 command and waits for completion.
203081ff398SHannes Reinecke  *
204081ff398SHannes Reinecke  * Return: command status
205081ff398SHannes Reinecke  */
myrb_exec_type3(struct myrb_hba * cb,enum myrb_cmd_opcode op,dma_addr_t addr)206081ff398SHannes Reinecke static unsigned short myrb_exec_type3(struct myrb_hba *cb,
207081ff398SHannes Reinecke 		enum myrb_cmd_opcode op, dma_addr_t addr)
208081ff398SHannes Reinecke {
209081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk;
210081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
211081ff398SHannes Reinecke 	unsigned short status;
212081ff398SHannes Reinecke 
213081ff398SHannes Reinecke 	mutex_lock(&cb->dcmd_mutex);
214081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
215081ff398SHannes Reinecke 	mbox->type3.id = MYRB_DCMD_TAG;
216081ff398SHannes Reinecke 	mbox->type3.opcode = op;
217081ff398SHannes Reinecke 	mbox->type3.addr = addr;
218081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
219081ff398SHannes Reinecke 	mutex_unlock(&cb->dcmd_mutex);
220081ff398SHannes Reinecke 	return status;
221081ff398SHannes Reinecke }
222081ff398SHannes Reinecke 
22312a1b740SLee Jones /*
224081ff398SHannes Reinecke  * myrb_exec_type3D - executes a type 3D command and waits for completion.
225081ff398SHannes Reinecke  *
226081ff398SHannes Reinecke  * Return: command status
227081ff398SHannes Reinecke  */
myrb_exec_type3D(struct myrb_hba * cb,enum myrb_cmd_opcode op,struct scsi_device * sdev,struct myrb_pdev_state * pdev_info)228081ff398SHannes Reinecke static unsigned short myrb_exec_type3D(struct myrb_hba *cb,
229081ff398SHannes Reinecke 		enum myrb_cmd_opcode op, struct scsi_device *sdev,
230081ff398SHannes Reinecke 		struct myrb_pdev_state *pdev_info)
231081ff398SHannes Reinecke {
232081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk;
233081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
234081ff398SHannes Reinecke 	unsigned short status;
235081ff398SHannes Reinecke 	dma_addr_t pdev_info_addr;
236081ff398SHannes Reinecke 
237081ff398SHannes Reinecke 	pdev_info_addr = dma_map_single(&cb->pdev->dev, pdev_info,
238081ff398SHannes Reinecke 					sizeof(struct myrb_pdev_state),
239081ff398SHannes Reinecke 					DMA_FROM_DEVICE);
240081ff398SHannes Reinecke 	if (dma_mapping_error(&cb->pdev->dev, pdev_info_addr))
241081ff398SHannes Reinecke 		return MYRB_STATUS_SUBSYS_FAILED;
242081ff398SHannes Reinecke 
243081ff398SHannes Reinecke 	mutex_lock(&cb->dcmd_mutex);
244081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
245081ff398SHannes Reinecke 	mbox->type3D.id = MYRB_DCMD_TAG;
246081ff398SHannes Reinecke 	mbox->type3D.opcode = op;
247081ff398SHannes Reinecke 	mbox->type3D.channel = sdev->channel;
248081ff398SHannes Reinecke 	mbox->type3D.target = sdev->id;
249081ff398SHannes Reinecke 	mbox->type3D.addr = pdev_info_addr;
250081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
251081ff398SHannes Reinecke 	mutex_unlock(&cb->dcmd_mutex);
252081ff398SHannes Reinecke 	dma_unmap_single(&cb->pdev->dev, pdev_info_addr,
253081ff398SHannes Reinecke 			 sizeof(struct myrb_pdev_state), DMA_FROM_DEVICE);
254081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS &&
255081ff398SHannes Reinecke 	    mbox->type3D.opcode == MYRB_CMD_GET_DEVICE_STATE_OLD)
256081ff398SHannes Reinecke 		myrb_translate_devstate(pdev_info);
257081ff398SHannes Reinecke 
258081ff398SHannes Reinecke 	return status;
259081ff398SHannes Reinecke }
260081ff398SHannes Reinecke 
261081ff398SHannes Reinecke static char *myrb_event_msg[] = {
262081ff398SHannes Reinecke 	"killed because write recovery failed",
263081ff398SHannes Reinecke 	"killed because of SCSI bus reset failure",
264081ff398SHannes Reinecke 	"killed because of double check condition",
265081ff398SHannes Reinecke 	"killed because it was removed",
266081ff398SHannes Reinecke 	"killed because of gross error on SCSI chip",
267081ff398SHannes Reinecke 	"killed because of bad tag returned from drive",
268081ff398SHannes Reinecke 	"killed because of timeout on SCSI command",
269081ff398SHannes Reinecke 	"killed because of reset SCSI command issued from system",
270081ff398SHannes Reinecke 	"killed because busy or parity error count exceeded limit",
271081ff398SHannes Reinecke 	"killed because of 'kill drive' command from system",
272081ff398SHannes Reinecke 	"killed because of selection timeout",
273081ff398SHannes Reinecke 	"killed due to SCSI phase sequence error",
274081ff398SHannes Reinecke 	"killed due to unknown status",
275081ff398SHannes Reinecke };
276081ff398SHannes Reinecke 
277081ff398SHannes Reinecke /**
278081ff398SHannes Reinecke  * myrb_get_event - get event log from HBA
279081ff398SHannes Reinecke  * @cb: pointer to the hba structure
280081ff398SHannes Reinecke  * @event: number of the event
281081ff398SHannes Reinecke  *
282081ff398SHannes Reinecke  * Execute a type 3E command and logs the event message
283081ff398SHannes Reinecke  */
myrb_get_event(struct myrb_hba * cb,unsigned int event)284081ff398SHannes Reinecke static void myrb_get_event(struct myrb_hba *cb, unsigned int event)
285081ff398SHannes Reinecke {
286081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
287081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
288081ff398SHannes Reinecke 	struct myrb_log_entry *ev_buf;
289081ff398SHannes Reinecke 	dma_addr_t ev_addr;
290081ff398SHannes Reinecke 	unsigned short status;
291081ff398SHannes Reinecke 
292081ff398SHannes Reinecke 	ev_buf = dma_alloc_coherent(&cb->pdev->dev,
293081ff398SHannes Reinecke 				    sizeof(struct myrb_log_entry),
294081ff398SHannes Reinecke 				    &ev_addr, GFP_KERNEL);
295081ff398SHannes Reinecke 	if (!ev_buf)
296081ff398SHannes Reinecke 		return;
297081ff398SHannes Reinecke 
298081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
299081ff398SHannes Reinecke 	mbox->type3E.id = MYRB_MCMD_TAG;
300081ff398SHannes Reinecke 	mbox->type3E.opcode = MYRB_CMD_EVENT_LOG_OPERATION;
301081ff398SHannes Reinecke 	mbox->type3E.optype = DAC960_V1_GetEventLogEntry;
302081ff398SHannes Reinecke 	mbox->type3E.opqual = 1;
303081ff398SHannes Reinecke 	mbox->type3E.ev_seq = event;
304081ff398SHannes Reinecke 	mbox->type3E.addr = ev_addr;
305081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
306081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS)
307081ff398SHannes Reinecke 		shost_printk(KERN_INFO, cb->host,
308081ff398SHannes Reinecke 			     "Failed to get event log %d, status %04x\n",
309081ff398SHannes Reinecke 			     event, status);
310081ff398SHannes Reinecke 
311081ff398SHannes Reinecke 	else if (ev_buf->seq_num == event) {
312081ff398SHannes Reinecke 		struct scsi_sense_hdr sshdr;
313081ff398SHannes Reinecke 
314081ff398SHannes Reinecke 		memset(&sshdr, 0, sizeof(sshdr));
315081ff398SHannes Reinecke 		scsi_normalize_sense(ev_buf->sense, 32, &sshdr);
316081ff398SHannes Reinecke 
317081ff398SHannes Reinecke 		if (sshdr.sense_key == VENDOR_SPECIFIC &&
318081ff398SHannes Reinecke 		    sshdr.asc == 0x80 &&
319081ff398SHannes Reinecke 		    sshdr.ascq < ARRAY_SIZE(myrb_event_msg))
320081ff398SHannes Reinecke 			shost_printk(KERN_CRIT, cb->host,
321081ff398SHannes Reinecke 				     "Physical drive %d:%d: %s\n",
322081ff398SHannes Reinecke 				     ev_buf->channel, ev_buf->target,
323081ff398SHannes Reinecke 				     myrb_event_msg[sshdr.ascq]);
324081ff398SHannes Reinecke 		else
325081ff398SHannes Reinecke 			shost_printk(KERN_CRIT, cb->host,
326081ff398SHannes Reinecke 				     "Physical drive %d:%d: Sense: %X/%02X/%02X\n",
327081ff398SHannes Reinecke 				     ev_buf->channel, ev_buf->target,
328081ff398SHannes Reinecke 				     sshdr.sense_key, sshdr.asc, sshdr.ascq);
329081ff398SHannes Reinecke 	}
330081ff398SHannes Reinecke 
331081ff398SHannes Reinecke 	dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_log_entry),
332081ff398SHannes Reinecke 			  ev_buf, ev_addr);
333081ff398SHannes Reinecke }
334081ff398SHannes Reinecke 
33512a1b740SLee Jones /*
336081ff398SHannes Reinecke  * myrb_get_errtable - retrieves the error table from the controller
337081ff398SHannes Reinecke  *
338081ff398SHannes Reinecke  * Executes a type 3 command and logs the error table from the controller.
339081ff398SHannes Reinecke  */
myrb_get_errtable(struct myrb_hba * cb)340081ff398SHannes Reinecke static void myrb_get_errtable(struct myrb_hba *cb)
341081ff398SHannes Reinecke {
342081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
343081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
344081ff398SHannes Reinecke 	unsigned short status;
345081ff398SHannes Reinecke 	struct myrb_error_entry old_table[MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS];
346081ff398SHannes Reinecke 
347081ff398SHannes Reinecke 	memcpy(&old_table, cb->err_table, sizeof(old_table));
348081ff398SHannes Reinecke 
349081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
350081ff398SHannes Reinecke 	mbox->type3.id = MYRB_MCMD_TAG;
351081ff398SHannes Reinecke 	mbox->type3.opcode = MYRB_CMD_GET_ERROR_TABLE;
352081ff398SHannes Reinecke 	mbox->type3.addr = cb->err_table_addr;
353081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
354081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS) {
355081ff398SHannes Reinecke 		struct myrb_error_entry *table = cb->err_table;
356081ff398SHannes Reinecke 		struct myrb_error_entry *new, *old;
357081ff398SHannes Reinecke 		size_t err_table_offset;
358081ff398SHannes Reinecke 		struct scsi_device *sdev;
359081ff398SHannes Reinecke 
360081ff398SHannes Reinecke 		shost_for_each_device(sdev, cb->host) {
361081ff398SHannes Reinecke 			if (sdev->channel >= myrb_logical_channel(cb->host))
362081ff398SHannes Reinecke 				continue;
363081ff398SHannes Reinecke 			err_table_offset = sdev->channel * MYRB_MAX_TARGETS
364081ff398SHannes Reinecke 				+ sdev->id;
365081ff398SHannes Reinecke 			new = table + err_table_offset;
366081ff398SHannes Reinecke 			old = &old_table[err_table_offset];
367081ff398SHannes Reinecke 			if (new->parity_err == old->parity_err &&
368081ff398SHannes Reinecke 			    new->soft_err == old->soft_err &&
369081ff398SHannes Reinecke 			    new->hard_err == old->hard_err &&
370081ff398SHannes Reinecke 			    new->misc_err == old->misc_err)
371081ff398SHannes Reinecke 				continue;
372081ff398SHannes Reinecke 			sdev_printk(KERN_CRIT, sdev,
373081ff398SHannes Reinecke 				    "Errors: Parity = %d, Soft = %d, Hard = %d, Misc = %d\n",
374081ff398SHannes Reinecke 				    new->parity_err, new->soft_err,
375081ff398SHannes Reinecke 				    new->hard_err, new->misc_err);
376081ff398SHannes Reinecke 		}
377081ff398SHannes Reinecke 	}
378081ff398SHannes Reinecke }
379081ff398SHannes Reinecke 
38012a1b740SLee Jones /*
381081ff398SHannes Reinecke  * myrb_get_ldev_info - retrieves the logical device table from the controller
382081ff398SHannes Reinecke  *
383081ff398SHannes Reinecke  * Executes a type 3 command and updates the logical device table.
384081ff398SHannes Reinecke  *
385081ff398SHannes Reinecke  * Return: command status
386081ff398SHannes Reinecke  */
myrb_get_ldev_info(struct myrb_hba * cb)387081ff398SHannes Reinecke static unsigned short myrb_get_ldev_info(struct myrb_hba *cb)
388081ff398SHannes Reinecke {
389081ff398SHannes Reinecke 	unsigned short status;
390081ff398SHannes Reinecke 	int ldev_num, ldev_cnt = cb->enquiry->ldev_count;
391081ff398SHannes Reinecke 	struct Scsi_Host *shost = cb->host;
392081ff398SHannes Reinecke 
393081ff398SHannes Reinecke 	status = myrb_exec_type3(cb, MYRB_CMD_GET_LDEV_INFO,
394081ff398SHannes Reinecke 				 cb->ldev_info_addr);
395081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS)
396081ff398SHannes Reinecke 		return status;
397081ff398SHannes Reinecke 
398081ff398SHannes Reinecke 	for (ldev_num = 0; ldev_num < ldev_cnt; ldev_num++) {
399081ff398SHannes Reinecke 		struct myrb_ldev_info *old = NULL;
400081ff398SHannes Reinecke 		struct myrb_ldev_info *new = cb->ldev_info_buf + ldev_num;
401081ff398SHannes Reinecke 		struct scsi_device *sdev;
402081ff398SHannes Reinecke 
403081ff398SHannes Reinecke 		sdev = scsi_device_lookup(shost, myrb_logical_channel(shost),
404081ff398SHannes Reinecke 					  ldev_num, 0);
405081ff398SHannes Reinecke 		if (!sdev) {
406081ff398SHannes Reinecke 			if (new->state == MYRB_DEVICE_OFFLINE)
407081ff398SHannes Reinecke 				continue;
408081ff398SHannes Reinecke 			shost_printk(KERN_INFO, shost,
409081ff398SHannes Reinecke 				     "Adding Logical Drive %d in state %s\n",
410081ff398SHannes Reinecke 				     ldev_num, myrb_devstate_name(new->state));
411081ff398SHannes Reinecke 			scsi_add_device(shost, myrb_logical_channel(shost),
412081ff398SHannes Reinecke 					ldev_num, 0);
413081ff398SHannes Reinecke 			continue;
414081ff398SHannes Reinecke 		}
415081ff398SHannes Reinecke 		old = sdev->hostdata;
416081ff398SHannes Reinecke 		if (new->state != old->state)
417081ff398SHannes Reinecke 			shost_printk(KERN_INFO, shost,
418081ff398SHannes Reinecke 				     "Logical Drive %d is now %s\n",
419081ff398SHannes Reinecke 				     ldev_num, myrb_devstate_name(new->state));
420081ff398SHannes Reinecke 		if (new->wb_enabled != old->wb_enabled)
421081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
422081ff398SHannes Reinecke 				    "Logical Drive is now WRITE %s\n",
423081ff398SHannes Reinecke 				    (new->wb_enabled ? "BACK" : "THRU"));
424081ff398SHannes Reinecke 		memcpy(old, new, sizeof(*new));
425081ff398SHannes Reinecke 		scsi_device_put(sdev);
426081ff398SHannes Reinecke 	}
427081ff398SHannes Reinecke 	return status;
428081ff398SHannes Reinecke }
429081ff398SHannes Reinecke 
43012a1b740SLee Jones /*
431081ff398SHannes Reinecke  * myrb_get_rbld_progress - get rebuild progress information
432081ff398SHannes Reinecke  *
433081ff398SHannes Reinecke  * Executes a type 3 command and returns the rebuild progress
434081ff398SHannes Reinecke  * information.
435081ff398SHannes Reinecke  *
436081ff398SHannes Reinecke  * Return: command status
437081ff398SHannes Reinecke  */
myrb_get_rbld_progress(struct myrb_hba * cb,struct myrb_rbld_progress * rbld)438081ff398SHannes Reinecke static unsigned short myrb_get_rbld_progress(struct myrb_hba *cb,
439081ff398SHannes Reinecke 		struct myrb_rbld_progress *rbld)
440081ff398SHannes Reinecke {
441081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
442081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
443081ff398SHannes Reinecke 	struct myrb_rbld_progress *rbld_buf;
444081ff398SHannes Reinecke 	dma_addr_t rbld_addr;
445081ff398SHannes Reinecke 	unsigned short status;
446081ff398SHannes Reinecke 
447081ff398SHannes Reinecke 	rbld_buf = dma_alloc_coherent(&cb->pdev->dev,
448081ff398SHannes Reinecke 				      sizeof(struct myrb_rbld_progress),
449081ff398SHannes Reinecke 				      &rbld_addr, GFP_KERNEL);
450081ff398SHannes Reinecke 	if (!rbld_buf)
451081ff398SHannes Reinecke 		return MYRB_STATUS_RBLD_NOT_CHECKED;
452081ff398SHannes Reinecke 
453081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
454081ff398SHannes Reinecke 	mbox->type3.id = MYRB_MCMD_TAG;
455081ff398SHannes Reinecke 	mbox->type3.opcode = MYRB_CMD_GET_REBUILD_PROGRESS;
456081ff398SHannes Reinecke 	mbox->type3.addr = rbld_addr;
457081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
458081ff398SHannes Reinecke 	if (rbld)
459081ff398SHannes Reinecke 		memcpy(rbld, rbld_buf, sizeof(struct myrb_rbld_progress));
460081ff398SHannes Reinecke 	dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_rbld_progress),
461081ff398SHannes Reinecke 			  rbld_buf, rbld_addr);
462081ff398SHannes Reinecke 	return status;
463081ff398SHannes Reinecke }
464081ff398SHannes Reinecke 
46512a1b740SLee Jones /*
466081ff398SHannes Reinecke  * myrb_update_rbld_progress - updates the rebuild status
467081ff398SHannes Reinecke  *
468081ff398SHannes Reinecke  * Updates the rebuild status for the attached logical devices.
469081ff398SHannes Reinecke  */
myrb_update_rbld_progress(struct myrb_hba * cb)470081ff398SHannes Reinecke static void myrb_update_rbld_progress(struct myrb_hba *cb)
471081ff398SHannes Reinecke {
472081ff398SHannes Reinecke 	struct myrb_rbld_progress rbld_buf;
473081ff398SHannes Reinecke 	unsigned short status;
474081ff398SHannes Reinecke 
475081ff398SHannes Reinecke 	status = myrb_get_rbld_progress(cb, &rbld_buf);
476081ff398SHannes Reinecke 	if (status == MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS &&
477081ff398SHannes Reinecke 	    cb->last_rbld_status == MYRB_STATUS_SUCCESS)
478081ff398SHannes Reinecke 		status = MYRB_STATUS_RBLD_SUCCESS;
479081ff398SHannes Reinecke 	if (status != MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS) {
480081ff398SHannes Reinecke 		unsigned int blocks_done =
481081ff398SHannes Reinecke 			rbld_buf.ldev_size - rbld_buf.blocks_left;
482081ff398SHannes Reinecke 		struct scsi_device *sdev;
483081ff398SHannes Reinecke 
484081ff398SHannes Reinecke 		sdev = scsi_device_lookup(cb->host,
485081ff398SHannes Reinecke 					  myrb_logical_channel(cb->host),
486081ff398SHannes Reinecke 					  rbld_buf.ldev_num, 0);
487081ff398SHannes Reinecke 		if (!sdev)
488081ff398SHannes Reinecke 			return;
489081ff398SHannes Reinecke 
490081ff398SHannes Reinecke 		switch (status) {
491081ff398SHannes Reinecke 		case MYRB_STATUS_SUCCESS:
492081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
493081ff398SHannes Reinecke 				    "Rebuild in Progress, %d%% completed\n",
494081ff398SHannes Reinecke 				    (100 * (blocks_done >> 7))
495081ff398SHannes Reinecke 				    / (rbld_buf.ldev_size >> 7));
496081ff398SHannes Reinecke 			break;
497081ff398SHannes Reinecke 		case MYRB_STATUS_RBLD_FAILED_LDEV_FAILURE:
498081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
499081ff398SHannes Reinecke 				    "Rebuild Failed due to Logical Drive Failure\n");
500081ff398SHannes Reinecke 			break;
501081ff398SHannes Reinecke 		case MYRB_STATUS_RBLD_FAILED_BADBLOCKS:
502081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
503081ff398SHannes Reinecke 				    "Rebuild Failed due to Bad Blocks on Other Drives\n");
504081ff398SHannes Reinecke 			break;
505081ff398SHannes Reinecke 		case MYRB_STATUS_RBLD_FAILED_NEW_DRIVE_FAILED:
506081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
507081ff398SHannes Reinecke 				    "Rebuild Failed due to Failure of Drive Being Rebuilt\n");
508081ff398SHannes Reinecke 			break;
509081ff398SHannes Reinecke 		case MYRB_STATUS_RBLD_SUCCESS:
510081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
511081ff398SHannes Reinecke 				    "Rebuild Completed Successfully\n");
512081ff398SHannes Reinecke 			break;
513081ff398SHannes Reinecke 		case MYRB_STATUS_RBLD_SUCCESS_TERMINATED:
514081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
515081ff398SHannes Reinecke 				     "Rebuild Successfully Terminated\n");
516081ff398SHannes Reinecke 			break;
517081ff398SHannes Reinecke 		default:
518081ff398SHannes Reinecke 			break;
519081ff398SHannes Reinecke 		}
520081ff398SHannes Reinecke 		scsi_device_put(sdev);
521081ff398SHannes Reinecke 	}
522081ff398SHannes Reinecke 	cb->last_rbld_status = status;
523081ff398SHannes Reinecke }
524081ff398SHannes Reinecke 
52512a1b740SLee Jones /*
526081ff398SHannes Reinecke  * myrb_get_cc_progress - retrieve the rebuild status
527081ff398SHannes Reinecke  *
528081ff398SHannes Reinecke  * Execute a type 3 Command and fetch the rebuild / consistency check
529081ff398SHannes Reinecke  * status.
530081ff398SHannes Reinecke  */
myrb_get_cc_progress(struct myrb_hba * cb)531081ff398SHannes Reinecke static void myrb_get_cc_progress(struct myrb_hba *cb)
532081ff398SHannes Reinecke {
533081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
534081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
535081ff398SHannes Reinecke 	struct myrb_rbld_progress *rbld_buf;
536081ff398SHannes Reinecke 	dma_addr_t rbld_addr;
537081ff398SHannes Reinecke 	unsigned short status;
538081ff398SHannes Reinecke 
539081ff398SHannes Reinecke 	rbld_buf = dma_alloc_coherent(&cb->pdev->dev,
540081ff398SHannes Reinecke 				      sizeof(struct myrb_rbld_progress),
541081ff398SHannes Reinecke 				      &rbld_addr, GFP_KERNEL);
542081ff398SHannes Reinecke 	if (!rbld_buf) {
543081ff398SHannes Reinecke 		cb->need_cc_status = true;
544081ff398SHannes Reinecke 		return;
545081ff398SHannes Reinecke 	}
546081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
547081ff398SHannes Reinecke 	mbox->type3.id = MYRB_MCMD_TAG;
548081ff398SHannes Reinecke 	mbox->type3.opcode = MYRB_CMD_REBUILD_STAT;
549081ff398SHannes Reinecke 	mbox->type3.addr = rbld_addr;
550081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
551081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS) {
552081ff398SHannes Reinecke 		unsigned int ldev_num = rbld_buf->ldev_num;
553081ff398SHannes Reinecke 		unsigned int ldev_size = rbld_buf->ldev_size;
554081ff398SHannes Reinecke 		unsigned int blocks_done =
555081ff398SHannes Reinecke 			ldev_size - rbld_buf->blocks_left;
556081ff398SHannes Reinecke 		struct scsi_device *sdev;
557081ff398SHannes Reinecke 
558081ff398SHannes Reinecke 		sdev = scsi_device_lookup(cb->host,
559081ff398SHannes Reinecke 					  myrb_logical_channel(cb->host),
560081ff398SHannes Reinecke 					  ldev_num, 0);
561081ff398SHannes Reinecke 		if (sdev) {
562081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
563081ff398SHannes Reinecke 				    "Consistency Check in Progress: %d%% completed\n",
564081ff398SHannes Reinecke 				    (100 * (blocks_done >> 7))
565081ff398SHannes Reinecke 				    / (ldev_size >> 7));
566081ff398SHannes Reinecke 			scsi_device_put(sdev);
567081ff398SHannes Reinecke 		}
568081ff398SHannes Reinecke 	}
569081ff398SHannes Reinecke 	dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_rbld_progress),
570081ff398SHannes Reinecke 			  rbld_buf, rbld_addr);
571081ff398SHannes Reinecke }
572081ff398SHannes Reinecke 
57312a1b740SLee Jones /*
574081ff398SHannes Reinecke  * myrb_bgi_control - updates background initialisation status
575081ff398SHannes Reinecke  *
576081ff398SHannes Reinecke  * Executes a type 3B command and updates the background initialisation status
577081ff398SHannes Reinecke  */
myrb_bgi_control(struct myrb_hba * cb)578081ff398SHannes Reinecke static void myrb_bgi_control(struct myrb_hba *cb)
579081ff398SHannes Reinecke {
580081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
581081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
582081ff398SHannes Reinecke 	struct myrb_bgi_status *bgi, *last_bgi;
583081ff398SHannes Reinecke 	dma_addr_t bgi_addr;
584081ff398SHannes Reinecke 	struct scsi_device *sdev = NULL;
585081ff398SHannes Reinecke 	unsigned short status;
586081ff398SHannes Reinecke 
587081ff398SHannes Reinecke 	bgi = dma_alloc_coherent(&cb->pdev->dev, sizeof(struct myrb_bgi_status),
588081ff398SHannes Reinecke 				 &bgi_addr, GFP_KERNEL);
589081ff398SHannes Reinecke 	if (!bgi) {
590081ff398SHannes Reinecke 		shost_printk(KERN_ERR, cb->host,
591081ff398SHannes Reinecke 			     "Failed to allocate bgi memory\n");
592081ff398SHannes Reinecke 		return;
593081ff398SHannes Reinecke 	}
594081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
595081ff398SHannes Reinecke 	mbox->type3B.id = MYRB_DCMD_TAG;
596081ff398SHannes Reinecke 	mbox->type3B.opcode = MYRB_CMD_BGI_CONTROL;
597081ff398SHannes Reinecke 	mbox->type3B.optype = 0x20;
598081ff398SHannes Reinecke 	mbox->type3B.addr = bgi_addr;
599081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
600081ff398SHannes Reinecke 	last_bgi = &cb->bgi_status;
601081ff398SHannes Reinecke 	sdev = scsi_device_lookup(cb->host,
602081ff398SHannes Reinecke 				  myrb_logical_channel(cb->host),
603081ff398SHannes Reinecke 				  bgi->ldev_num, 0);
604081ff398SHannes Reinecke 	switch (status) {
605081ff398SHannes Reinecke 	case MYRB_STATUS_SUCCESS:
606081ff398SHannes Reinecke 		switch (bgi->status) {
607081ff398SHannes Reinecke 		case MYRB_BGI_INVALID:
608081ff398SHannes Reinecke 			break;
609081ff398SHannes Reinecke 		case MYRB_BGI_STARTED:
610081ff398SHannes Reinecke 			if (!sdev)
611081ff398SHannes Reinecke 				break;
612081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
613081ff398SHannes Reinecke 				    "Background Initialization Started\n");
614081ff398SHannes Reinecke 			break;
615081ff398SHannes Reinecke 		case MYRB_BGI_INPROGRESS:
616081ff398SHannes Reinecke 			if (!sdev)
617081ff398SHannes Reinecke 				break;
618081ff398SHannes Reinecke 			if (bgi->blocks_done == last_bgi->blocks_done &&
619081ff398SHannes Reinecke 			    bgi->ldev_num == last_bgi->ldev_num)
620081ff398SHannes Reinecke 				break;
621081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
622081ff398SHannes Reinecke 				 "Background Initialization in Progress: %d%% completed\n",
623081ff398SHannes Reinecke 				 (100 * (bgi->blocks_done >> 7))
624081ff398SHannes Reinecke 				 / (bgi->ldev_size >> 7));
625081ff398SHannes Reinecke 			break;
626081ff398SHannes Reinecke 		case MYRB_BGI_SUSPENDED:
627081ff398SHannes Reinecke 			if (!sdev)
628081ff398SHannes Reinecke 				break;
629081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
630081ff398SHannes Reinecke 				    "Background Initialization Suspended\n");
631081ff398SHannes Reinecke 			break;
632081ff398SHannes Reinecke 		case MYRB_BGI_CANCELLED:
633081ff398SHannes Reinecke 			if (!sdev)
634081ff398SHannes Reinecke 				break;
635081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
636081ff398SHannes Reinecke 				    "Background Initialization Cancelled\n");
637081ff398SHannes Reinecke 			break;
638081ff398SHannes Reinecke 		}
639081ff398SHannes Reinecke 		memcpy(&cb->bgi_status, bgi, sizeof(struct myrb_bgi_status));
640081ff398SHannes Reinecke 		break;
641081ff398SHannes Reinecke 	case MYRB_STATUS_BGI_SUCCESS:
642081ff398SHannes Reinecke 		if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS)
643081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
644081ff398SHannes Reinecke 				    "Background Initialization Completed Successfully\n");
645081ff398SHannes Reinecke 		cb->bgi_status.status = MYRB_BGI_INVALID;
646081ff398SHannes Reinecke 		break;
647081ff398SHannes Reinecke 	case MYRB_STATUS_BGI_ABORTED:
648081ff398SHannes Reinecke 		if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS)
649081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
650081ff398SHannes Reinecke 				    "Background Initialization Aborted\n");
651df561f66SGustavo A. R. Silva 		fallthrough;
652081ff398SHannes Reinecke 	case MYRB_STATUS_NO_BGI_INPROGRESS:
653081ff398SHannes Reinecke 		cb->bgi_status.status = MYRB_BGI_INVALID;
654081ff398SHannes Reinecke 		break;
655081ff398SHannes Reinecke 	}
656081ff398SHannes Reinecke 	if (sdev)
657081ff398SHannes Reinecke 		scsi_device_put(sdev);
658081ff398SHannes Reinecke 	dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_bgi_status),
659081ff398SHannes Reinecke 			  bgi, bgi_addr);
660081ff398SHannes Reinecke }
661081ff398SHannes Reinecke 
66212a1b740SLee Jones /*
663081ff398SHannes Reinecke  * myrb_hba_enquiry - updates the controller status
664081ff398SHannes Reinecke  *
665081ff398SHannes Reinecke  * Executes a DAC_V1_Enquiry command and updates the controller status.
666081ff398SHannes Reinecke  *
667081ff398SHannes Reinecke  * Return: command status
668081ff398SHannes Reinecke  */
myrb_hba_enquiry(struct myrb_hba * cb)669081ff398SHannes Reinecke static unsigned short myrb_hba_enquiry(struct myrb_hba *cb)
670081ff398SHannes Reinecke {
671081ff398SHannes Reinecke 	struct myrb_enquiry old, *new;
672081ff398SHannes Reinecke 	unsigned short status;
673081ff398SHannes Reinecke 
674081ff398SHannes Reinecke 	memcpy(&old, cb->enquiry, sizeof(struct myrb_enquiry));
675081ff398SHannes Reinecke 
676081ff398SHannes Reinecke 	status = myrb_exec_type3(cb, MYRB_CMD_ENQUIRY, cb->enquiry_addr);
677081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS)
678081ff398SHannes Reinecke 		return status;
679081ff398SHannes Reinecke 
680081ff398SHannes Reinecke 	new = cb->enquiry;
681081ff398SHannes Reinecke 	if (new->ldev_count > old.ldev_count) {
682081ff398SHannes Reinecke 		int ldev_num = old.ldev_count - 1;
683081ff398SHannes Reinecke 
684081ff398SHannes Reinecke 		while (++ldev_num < new->ldev_count)
685081ff398SHannes Reinecke 			shost_printk(KERN_CRIT, cb->host,
686081ff398SHannes Reinecke 				     "Logical Drive %d Now Exists\n",
687081ff398SHannes Reinecke 				     ldev_num);
688081ff398SHannes Reinecke 	}
689081ff398SHannes Reinecke 	if (new->ldev_count < old.ldev_count) {
690081ff398SHannes Reinecke 		int ldev_num = new->ldev_count - 1;
691081ff398SHannes Reinecke 
692081ff398SHannes Reinecke 		while (++ldev_num < old.ldev_count)
693081ff398SHannes Reinecke 			shost_printk(KERN_CRIT, cb->host,
694081ff398SHannes Reinecke 				     "Logical Drive %d No Longer Exists\n",
695081ff398SHannes Reinecke 				     ldev_num);
696081ff398SHannes Reinecke 	}
697081ff398SHannes Reinecke 	if (new->status.deferred != old.status.deferred)
698081ff398SHannes Reinecke 		shost_printk(KERN_CRIT, cb->host,
699081ff398SHannes Reinecke 			     "Deferred Write Error Flag is now %s\n",
700081ff398SHannes Reinecke 			     (new->status.deferred ? "TRUE" : "FALSE"));
701081ff398SHannes Reinecke 	if (new->ev_seq != old.ev_seq) {
702081ff398SHannes Reinecke 		cb->new_ev_seq = new->ev_seq;
703081ff398SHannes Reinecke 		cb->need_err_info = true;
704081ff398SHannes Reinecke 		shost_printk(KERN_INFO, cb->host,
705081ff398SHannes Reinecke 			     "Event log %d/%d (%d/%d) available\n",
706081ff398SHannes Reinecke 			     cb->old_ev_seq, cb->new_ev_seq,
707081ff398SHannes Reinecke 			     old.ev_seq, new->ev_seq);
708081ff398SHannes Reinecke 	}
709081ff398SHannes Reinecke 	if ((new->ldev_critical > 0 &&
710081ff398SHannes Reinecke 	     new->ldev_critical != old.ldev_critical) ||
711081ff398SHannes Reinecke 	    (new->ldev_offline > 0 &&
712081ff398SHannes Reinecke 	     new->ldev_offline != old.ldev_offline) ||
713081ff398SHannes Reinecke 	    (new->ldev_count != old.ldev_count)) {
714081ff398SHannes Reinecke 		shost_printk(KERN_INFO, cb->host,
715081ff398SHannes Reinecke 			     "Logical drive count changed (%d/%d/%d)\n",
716081ff398SHannes Reinecke 			     new->ldev_critical,
717081ff398SHannes Reinecke 			     new->ldev_offline,
718081ff398SHannes Reinecke 			     new->ldev_count);
719081ff398SHannes Reinecke 		cb->need_ldev_info = true;
720081ff398SHannes Reinecke 	}
721081ff398SHannes Reinecke 	if (new->pdev_dead > 0 ||
722081ff398SHannes Reinecke 	    new->pdev_dead != old.pdev_dead ||
723081ff398SHannes Reinecke 	    time_after_eq(jiffies, cb->secondary_monitor_time
724081ff398SHannes Reinecke 			  + MYRB_SECONDARY_MONITOR_INTERVAL)) {
725081ff398SHannes Reinecke 		cb->need_bgi_status = cb->bgi_status_supported;
726081ff398SHannes Reinecke 		cb->secondary_monitor_time = jiffies;
727081ff398SHannes Reinecke 	}
728081ff398SHannes Reinecke 	if (new->rbld == MYRB_STDBY_RBLD_IN_PROGRESS ||
729081ff398SHannes Reinecke 	    new->rbld == MYRB_BG_RBLD_IN_PROGRESS ||
730081ff398SHannes Reinecke 	    old.rbld == MYRB_STDBY_RBLD_IN_PROGRESS ||
731081ff398SHannes Reinecke 	    old.rbld == MYRB_BG_RBLD_IN_PROGRESS) {
732081ff398SHannes Reinecke 		cb->need_rbld = true;
733081ff398SHannes Reinecke 		cb->rbld_first = (new->ldev_critical < old.ldev_critical);
734081ff398SHannes Reinecke 	}
735081ff398SHannes Reinecke 	if (old.rbld == MYRB_BG_CHECK_IN_PROGRESS)
736081ff398SHannes Reinecke 		switch (new->rbld) {
737081ff398SHannes Reinecke 		case MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS:
738081ff398SHannes Reinecke 			shost_printk(KERN_INFO, cb->host,
739081ff398SHannes Reinecke 				     "Consistency Check Completed Successfully\n");
740081ff398SHannes Reinecke 			break;
741081ff398SHannes Reinecke 		case MYRB_STDBY_RBLD_IN_PROGRESS:
742081ff398SHannes Reinecke 		case MYRB_BG_RBLD_IN_PROGRESS:
743081ff398SHannes Reinecke 			break;
744081ff398SHannes Reinecke 		case MYRB_BG_CHECK_IN_PROGRESS:
745081ff398SHannes Reinecke 			cb->need_cc_status = true;
746081ff398SHannes Reinecke 			break;
747081ff398SHannes Reinecke 		case MYRB_STDBY_RBLD_COMPLETED_WITH_ERROR:
748081ff398SHannes Reinecke 			shost_printk(KERN_INFO, cb->host,
749081ff398SHannes Reinecke 				     "Consistency Check Completed with Error\n");
750081ff398SHannes Reinecke 			break;
751081ff398SHannes Reinecke 		case MYRB_BG_RBLD_OR_CHECK_FAILED_DRIVE_FAILED:
752081ff398SHannes Reinecke 			shost_printk(KERN_INFO, cb->host,
753081ff398SHannes Reinecke 				     "Consistency Check Failed - Physical Device Failed\n");
754081ff398SHannes Reinecke 			break;
755081ff398SHannes Reinecke 		case MYRB_BG_RBLD_OR_CHECK_FAILED_LDEV_FAILED:
756081ff398SHannes Reinecke 			shost_printk(KERN_INFO, cb->host,
757081ff398SHannes Reinecke 				     "Consistency Check Failed - Logical Drive Failed\n");
758081ff398SHannes Reinecke 			break;
759081ff398SHannes Reinecke 		case MYRB_BG_RBLD_OR_CHECK_FAILED_OTHER:
760081ff398SHannes Reinecke 			shost_printk(KERN_INFO, cb->host,
761081ff398SHannes Reinecke 				     "Consistency Check Failed - Other Causes\n");
762081ff398SHannes Reinecke 			break;
763081ff398SHannes Reinecke 		case MYRB_BG_RBLD_OR_CHECK_SUCCESS_TERMINATED:
764081ff398SHannes Reinecke 			shost_printk(KERN_INFO, cb->host,
765081ff398SHannes Reinecke 				     "Consistency Check Successfully Terminated\n");
766081ff398SHannes Reinecke 			break;
767081ff398SHannes Reinecke 		}
768081ff398SHannes Reinecke 	else if (new->rbld == MYRB_BG_CHECK_IN_PROGRESS)
769081ff398SHannes Reinecke 		cb->need_cc_status = true;
770081ff398SHannes Reinecke 
771081ff398SHannes Reinecke 	return MYRB_STATUS_SUCCESS;
772081ff398SHannes Reinecke }
773081ff398SHannes Reinecke 
77412a1b740SLee Jones /*
775081ff398SHannes Reinecke  * myrb_set_pdev_state - sets the device state for a physical device
776081ff398SHannes Reinecke  *
777081ff398SHannes Reinecke  * Return: command status
778081ff398SHannes Reinecke  */
myrb_set_pdev_state(struct myrb_hba * cb,struct scsi_device * sdev,enum myrb_devstate state)779081ff398SHannes Reinecke static unsigned short myrb_set_pdev_state(struct myrb_hba *cb,
780081ff398SHannes Reinecke 		struct scsi_device *sdev, enum myrb_devstate state)
781081ff398SHannes Reinecke {
782081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk;
783081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
784081ff398SHannes Reinecke 	unsigned short status;
785081ff398SHannes Reinecke 
786081ff398SHannes Reinecke 	mutex_lock(&cb->dcmd_mutex);
787081ff398SHannes Reinecke 	mbox->type3D.opcode = MYRB_CMD_START_DEVICE;
788081ff398SHannes Reinecke 	mbox->type3D.id = MYRB_DCMD_TAG;
789081ff398SHannes Reinecke 	mbox->type3D.channel = sdev->channel;
790081ff398SHannes Reinecke 	mbox->type3D.target = sdev->id;
791081ff398SHannes Reinecke 	mbox->type3D.state = state & 0x1F;
792081ff398SHannes Reinecke 	status = myrb_exec_cmd(cb, cmd_blk);
793081ff398SHannes Reinecke 	mutex_unlock(&cb->dcmd_mutex);
794081ff398SHannes Reinecke 
795081ff398SHannes Reinecke 	return status;
796081ff398SHannes Reinecke }
797081ff398SHannes Reinecke 
79812a1b740SLee Jones /*
799081ff398SHannes Reinecke  * myrb_enable_mmio - enables the Memory Mailbox Interface
800081ff398SHannes Reinecke  *
801081ff398SHannes Reinecke  * PD and P controller types have no memory mailbox, but still need the
802081ff398SHannes Reinecke  * other dma mapped memory.
803081ff398SHannes Reinecke  *
804081ff398SHannes Reinecke  * Return: true on success, false otherwise.
805081ff398SHannes Reinecke  */
myrb_enable_mmio(struct myrb_hba * cb,mbox_mmio_init_t mmio_init_fn)806081ff398SHannes Reinecke static bool myrb_enable_mmio(struct myrb_hba *cb, mbox_mmio_init_t mmio_init_fn)
807081ff398SHannes Reinecke {
808081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
809081ff398SHannes Reinecke 	struct pci_dev *pdev = cb->pdev;
810081ff398SHannes Reinecke 	size_t err_table_size;
811081ff398SHannes Reinecke 	size_t ldev_info_size;
812081ff398SHannes Reinecke 	union myrb_cmd_mbox *cmd_mbox_mem;
813081ff398SHannes Reinecke 	struct myrb_stat_mbox *stat_mbox_mem;
814081ff398SHannes Reinecke 	union myrb_cmd_mbox mbox;
815081ff398SHannes Reinecke 	unsigned short status;
816081ff398SHannes Reinecke 
817081ff398SHannes Reinecke 	memset(&mbox, 0, sizeof(union myrb_cmd_mbox));
818081ff398SHannes Reinecke 
819081ff398SHannes Reinecke 	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
820081ff398SHannes Reinecke 		dev_err(&pdev->dev, "DMA mask out of range\n");
821081ff398SHannes Reinecke 		return false;
822081ff398SHannes Reinecke 	}
823081ff398SHannes Reinecke 
824081ff398SHannes Reinecke 	cb->enquiry = dma_alloc_coherent(&pdev->dev,
825081ff398SHannes Reinecke 					 sizeof(struct myrb_enquiry),
826081ff398SHannes Reinecke 					 &cb->enquiry_addr, GFP_KERNEL);
827081ff398SHannes Reinecke 	if (!cb->enquiry)
828081ff398SHannes Reinecke 		return false;
829081ff398SHannes Reinecke 
830081ff398SHannes Reinecke 	err_table_size = sizeof(struct myrb_error_entry) *
831081ff398SHannes Reinecke 		MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS;
832081ff398SHannes Reinecke 	cb->err_table = dma_alloc_coherent(&pdev->dev, err_table_size,
833081ff398SHannes Reinecke 					   &cb->err_table_addr, GFP_KERNEL);
834081ff398SHannes Reinecke 	if (!cb->err_table)
835081ff398SHannes Reinecke 		return false;
836081ff398SHannes Reinecke 
837081ff398SHannes Reinecke 	ldev_info_size = sizeof(struct myrb_ldev_info) * MYRB_MAX_LDEVS;
838081ff398SHannes Reinecke 	cb->ldev_info_buf = dma_alloc_coherent(&pdev->dev, ldev_info_size,
839081ff398SHannes Reinecke 					       &cb->ldev_info_addr, GFP_KERNEL);
840081ff398SHannes Reinecke 	if (!cb->ldev_info_buf)
841081ff398SHannes Reinecke 		return false;
842081ff398SHannes Reinecke 
843081ff398SHannes Reinecke 	/*
844081ff398SHannes Reinecke 	 * Skip mailbox initialisation for PD and P Controllers
845081ff398SHannes Reinecke 	 */
846081ff398SHannes Reinecke 	if (!mmio_init_fn)
847081ff398SHannes Reinecke 		return true;
848081ff398SHannes Reinecke 
849081ff398SHannes Reinecke 	/* These are the base addresses for the command memory mailbox array */
850081ff398SHannes Reinecke 	cb->cmd_mbox_size =  MYRB_CMD_MBOX_COUNT * sizeof(union myrb_cmd_mbox);
851081ff398SHannes Reinecke 	cb->first_cmd_mbox = dma_alloc_coherent(&pdev->dev,
852081ff398SHannes Reinecke 						cb->cmd_mbox_size,
853081ff398SHannes Reinecke 						&cb->cmd_mbox_addr,
854081ff398SHannes Reinecke 						GFP_KERNEL);
855081ff398SHannes Reinecke 	if (!cb->first_cmd_mbox)
856081ff398SHannes Reinecke 		return false;
857081ff398SHannes Reinecke 
858081ff398SHannes Reinecke 	cmd_mbox_mem = cb->first_cmd_mbox;
859081ff398SHannes Reinecke 	cmd_mbox_mem += MYRB_CMD_MBOX_COUNT - 1;
860081ff398SHannes Reinecke 	cb->last_cmd_mbox = cmd_mbox_mem;
861081ff398SHannes Reinecke 	cb->next_cmd_mbox = cb->first_cmd_mbox;
862081ff398SHannes Reinecke 	cb->prev_cmd_mbox1 = cb->last_cmd_mbox;
863081ff398SHannes Reinecke 	cb->prev_cmd_mbox2 = cb->last_cmd_mbox - 1;
864081ff398SHannes Reinecke 
865081ff398SHannes Reinecke 	/* These are the base addresses for the status memory mailbox array */
866081ff398SHannes Reinecke 	cb->stat_mbox_size = MYRB_STAT_MBOX_COUNT *
867081ff398SHannes Reinecke 	    sizeof(struct myrb_stat_mbox);
868081ff398SHannes Reinecke 	cb->first_stat_mbox = dma_alloc_coherent(&pdev->dev,
869081ff398SHannes Reinecke 						 cb->stat_mbox_size,
870081ff398SHannes Reinecke 						 &cb->stat_mbox_addr,
871081ff398SHannes Reinecke 						 GFP_KERNEL);
872081ff398SHannes Reinecke 	if (!cb->first_stat_mbox)
873081ff398SHannes Reinecke 		return false;
874081ff398SHannes Reinecke 
875081ff398SHannes Reinecke 	stat_mbox_mem = cb->first_stat_mbox;
876081ff398SHannes Reinecke 	stat_mbox_mem += MYRB_STAT_MBOX_COUNT - 1;
877081ff398SHannes Reinecke 	cb->last_stat_mbox = stat_mbox_mem;
878081ff398SHannes Reinecke 	cb->next_stat_mbox = cb->first_stat_mbox;
879081ff398SHannes Reinecke 
880081ff398SHannes Reinecke 	/* Enable the Memory Mailbox Interface. */
881081ff398SHannes Reinecke 	cb->dual_mode_interface = true;
882081ff398SHannes Reinecke 	mbox.typeX.opcode = 0x2B;
883081ff398SHannes Reinecke 	mbox.typeX.id = 0;
884081ff398SHannes Reinecke 	mbox.typeX.opcode2 = 0x14;
885081ff398SHannes Reinecke 	mbox.typeX.cmd_mbox_addr = cb->cmd_mbox_addr;
886081ff398SHannes Reinecke 	mbox.typeX.stat_mbox_addr = cb->stat_mbox_addr;
887081ff398SHannes Reinecke 
888081ff398SHannes Reinecke 	status = mmio_init_fn(pdev, base, &mbox);
889081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS) {
890081ff398SHannes Reinecke 		cb->dual_mode_interface = false;
891081ff398SHannes Reinecke 		mbox.typeX.opcode2 = 0x10;
892081ff398SHannes Reinecke 		status = mmio_init_fn(pdev, base, &mbox);
893081ff398SHannes Reinecke 		if (status != MYRB_STATUS_SUCCESS) {
894081ff398SHannes Reinecke 			dev_err(&pdev->dev,
895081ff398SHannes Reinecke 				"Failed to enable mailbox, statux %02X\n",
896081ff398SHannes Reinecke 				status);
897081ff398SHannes Reinecke 			return false;
898081ff398SHannes Reinecke 		}
899081ff398SHannes Reinecke 	}
900081ff398SHannes Reinecke 	return true;
901081ff398SHannes Reinecke }
902081ff398SHannes Reinecke 
90312a1b740SLee Jones /*
904081ff398SHannes Reinecke  * myrb_get_hba_config - reads the configuration information
905081ff398SHannes Reinecke  *
906081ff398SHannes Reinecke  * Reads the configuration information from the controller and
907081ff398SHannes Reinecke  * initializes the controller structure.
908081ff398SHannes Reinecke  *
909081ff398SHannes Reinecke  * Return: 0 on success, errno otherwise
910081ff398SHannes Reinecke  */
myrb_get_hba_config(struct myrb_hba * cb)911081ff398SHannes Reinecke static int myrb_get_hba_config(struct myrb_hba *cb)
912081ff398SHannes Reinecke {
913081ff398SHannes Reinecke 	struct myrb_enquiry2 *enquiry2;
914081ff398SHannes Reinecke 	dma_addr_t enquiry2_addr;
915081ff398SHannes Reinecke 	struct myrb_config2 *config2;
916081ff398SHannes Reinecke 	dma_addr_t config2_addr;
917081ff398SHannes Reinecke 	struct Scsi_Host *shost = cb->host;
918081ff398SHannes Reinecke 	struct pci_dev *pdev = cb->pdev;
919081ff398SHannes Reinecke 	int pchan_max = 0, pchan_cur = 0;
920081ff398SHannes Reinecke 	unsigned short status;
921081ff398SHannes Reinecke 	int ret = -ENODEV, memsize = 0;
922081ff398SHannes Reinecke 
923081ff398SHannes Reinecke 	enquiry2 = dma_alloc_coherent(&pdev->dev, sizeof(struct myrb_enquiry2),
924081ff398SHannes Reinecke 				      &enquiry2_addr, GFP_KERNEL);
925081ff398SHannes Reinecke 	if (!enquiry2) {
926081ff398SHannes Reinecke 		shost_printk(KERN_ERR, cb->host,
927081ff398SHannes Reinecke 			     "Failed to allocate V1 enquiry2 memory\n");
928081ff398SHannes Reinecke 		return -ENOMEM;
929081ff398SHannes Reinecke 	}
930081ff398SHannes Reinecke 	config2 = dma_alloc_coherent(&pdev->dev, sizeof(struct myrb_config2),
931081ff398SHannes Reinecke 				     &config2_addr, GFP_KERNEL);
932081ff398SHannes Reinecke 	if (!config2) {
933081ff398SHannes Reinecke 		shost_printk(KERN_ERR, cb->host,
934081ff398SHannes Reinecke 			     "Failed to allocate V1 config2 memory\n");
935081ff398SHannes Reinecke 		dma_free_coherent(&pdev->dev, sizeof(struct myrb_enquiry2),
936081ff398SHannes Reinecke 				  enquiry2, enquiry2_addr);
937081ff398SHannes Reinecke 		return -ENOMEM;
938081ff398SHannes Reinecke 	}
939081ff398SHannes Reinecke 	mutex_lock(&cb->dma_mutex);
940081ff398SHannes Reinecke 	status = myrb_hba_enquiry(cb);
941081ff398SHannes Reinecke 	mutex_unlock(&cb->dma_mutex);
942081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS) {
943081ff398SHannes Reinecke 		shost_printk(KERN_WARNING, cb->host,
944081ff398SHannes Reinecke 			     "Failed it issue V1 Enquiry\n");
945081ff398SHannes Reinecke 		goto out_free;
946081ff398SHannes Reinecke 	}
947081ff398SHannes Reinecke 
948081ff398SHannes Reinecke 	status = myrb_exec_type3(cb, MYRB_CMD_ENQUIRY2, enquiry2_addr);
949081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS) {
950081ff398SHannes Reinecke 		shost_printk(KERN_WARNING, cb->host,
951081ff398SHannes Reinecke 			     "Failed to issue V1 Enquiry2\n");
952081ff398SHannes Reinecke 		goto out_free;
953081ff398SHannes Reinecke 	}
954081ff398SHannes Reinecke 
955081ff398SHannes Reinecke 	status = myrb_exec_type3(cb, MYRB_CMD_READ_CONFIG2, config2_addr);
956081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS) {
957081ff398SHannes Reinecke 		shost_printk(KERN_WARNING, cb->host,
958081ff398SHannes Reinecke 			     "Failed to issue ReadConfig2\n");
959081ff398SHannes Reinecke 		goto out_free;
960081ff398SHannes Reinecke 	}
961081ff398SHannes Reinecke 
962081ff398SHannes Reinecke 	status = myrb_get_ldev_info(cb);
963081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS) {
964081ff398SHannes Reinecke 		shost_printk(KERN_WARNING, cb->host,
965081ff398SHannes Reinecke 			     "Failed to get logical drive information\n");
966081ff398SHannes Reinecke 		goto out_free;
967081ff398SHannes Reinecke 	}
968081ff398SHannes Reinecke 
969081ff398SHannes Reinecke 	/*
970081ff398SHannes Reinecke 	 * Initialize the Controller Model Name and Full Model Name fields.
971081ff398SHannes Reinecke 	 */
972081ff398SHannes Reinecke 	switch (enquiry2->hw.sub_model) {
973081ff398SHannes Reinecke 	case DAC960_V1_P_PD_PU:
974081ff398SHannes Reinecke 		if (enquiry2->scsi_cap.bus_speed == MYRB_SCSI_SPEED_ULTRA)
975081ff398SHannes Reinecke 			strcpy(cb->model_name, "DAC960PU");
976081ff398SHannes Reinecke 		else
977081ff398SHannes Reinecke 			strcpy(cb->model_name, "DAC960PD");
978081ff398SHannes Reinecke 		break;
979081ff398SHannes Reinecke 	case DAC960_V1_PL:
980081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PL");
981081ff398SHannes Reinecke 		break;
982081ff398SHannes Reinecke 	case DAC960_V1_PG:
983081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PG");
984081ff398SHannes Reinecke 		break;
985081ff398SHannes Reinecke 	case DAC960_V1_PJ:
986081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PJ");
987081ff398SHannes Reinecke 		break;
988081ff398SHannes Reinecke 	case DAC960_V1_PR:
989081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PR");
990081ff398SHannes Reinecke 		break;
991081ff398SHannes Reinecke 	case DAC960_V1_PT:
992081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PT");
993081ff398SHannes Reinecke 		break;
994081ff398SHannes Reinecke 	case DAC960_V1_PTL0:
995081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PTL0");
996081ff398SHannes Reinecke 		break;
997081ff398SHannes Reinecke 	case DAC960_V1_PRL:
998081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PRL");
999081ff398SHannes Reinecke 		break;
1000081ff398SHannes Reinecke 	case DAC960_V1_PTL1:
1001081ff398SHannes Reinecke 		strcpy(cb->model_name, "DAC960PTL1");
1002081ff398SHannes Reinecke 		break;
1003081ff398SHannes Reinecke 	case DAC960_V1_1164P:
1004081ff398SHannes Reinecke 		strcpy(cb->model_name, "eXtremeRAID 1100");
1005081ff398SHannes Reinecke 		break;
1006081ff398SHannes Reinecke 	default:
1007081ff398SHannes Reinecke 		shost_printk(KERN_WARNING, cb->host,
1008081ff398SHannes Reinecke 			     "Unknown Model %X\n",
1009081ff398SHannes Reinecke 			     enquiry2->hw.sub_model);
1010081ff398SHannes Reinecke 		goto out;
1011081ff398SHannes Reinecke 	}
1012081ff398SHannes Reinecke 	/*
1013081ff398SHannes Reinecke 	 * Initialize the Controller Firmware Version field and verify that it
1014081ff398SHannes Reinecke 	 * is a supported firmware version.
1015081ff398SHannes Reinecke 	 * The supported firmware versions are:
1016081ff398SHannes Reinecke 	 *
1017081ff398SHannes Reinecke 	 * DAC1164P		    5.06 and above
1018081ff398SHannes Reinecke 	 * DAC960PTL/PRL/PJ/PG	    4.06 and above
1019081ff398SHannes Reinecke 	 * DAC960PU/PD/PL	    3.51 and above
1020081ff398SHannes Reinecke 	 * DAC960PU/PD/PL/P	    2.73 and above
1021081ff398SHannes Reinecke 	 */
1022081ff398SHannes Reinecke #if defined(CONFIG_ALPHA)
1023081ff398SHannes Reinecke 	/*
1024081ff398SHannes Reinecke 	 * DEC Alpha machines were often equipped with DAC960 cards that were
1025081ff398SHannes Reinecke 	 * OEMed from Mylex, and had their own custom firmware. Version 2.70,
1026081ff398SHannes Reinecke 	 * the last custom FW revision to be released by DEC for these older
1027081ff398SHannes Reinecke 	 * controllers, appears to work quite well with this driver.
1028081ff398SHannes Reinecke 	 *
1029081ff398SHannes Reinecke 	 * Cards tested successfully were several versions each of the PD and
1030081ff398SHannes Reinecke 	 * PU, called by DEC the KZPSC and KZPAC, respectively, and having
1031081ff398SHannes Reinecke 	 * the Manufacturer Numbers (from Mylex), usually on a sticker on the
1032081ff398SHannes Reinecke 	 * back of the board, of:
1033081ff398SHannes Reinecke 	 *
1034081ff398SHannes Reinecke 	 * KZPSC:  D040347 (1-channel) or D040348 (2-channel)
1035081ff398SHannes Reinecke 	 *         or D040349 (3-channel)
1036081ff398SHannes Reinecke 	 * KZPAC:  D040395 (1-channel) or D040396 (2-channel)
1037081ff398SHannes Reinecke 	 *         or D040397 (3-channel)
1038081ff398SHannes Reinecke 	 */
1039081ff398SHannes Reinecke # define FIRMWARE_27X	"2.70"
1040081ff398SHannes Reinecke #else
1041081ff398SHannes Reinecke # define FIRMWARE_27X	"2.73"
1042081ff398SHannes Reinecke #endif
1043081ff398SHannes Reinecke 
1044081ff398SHannes Reinecke 	if (enquiry2->fw.major_version == 0) {
1045081ff398SHannes Reinecke 		enquiry2->fw.major_version = cb->enquiry->fw_major_version;
1046081ff398SHannes Reinecke 		enquiry2->fw.minor_version = cb->enquiry->fw_minor_version;
1047081ff398SHannes Reinecke 		enquiry2->fw.firmware_type = '0';
1048081ff398SHannes Reinecke 		enquiry2->fw.turn_id = 0;
1049081ff398SHannes Reinecke 	}
1050f8f4adc1SArnd Bergmann 	snprintf(cb->fw_version, sizeof(cb->fw_version),
1051fc29f04aSYe Bin 		"%u.%02u-%c-%02u",
1052081ff398SHannes Reinecke 		enquiry2->fw.major_version,
1053081ff398SHannes Reinecke 		enquiry2->fw.minor_version,
1054081ff398SHannes Reinecke 		enquiry2->fw.firmware_type,
1055081ff398SHannes Reinecke 		enquiry2->fw.turn_id);
1056081ff398SHannes Reinecke 	if (!((enquiry2->fw.major_version == 5 &&
1057081ff398SHannes Reinecke 	       enquiry2->fw.minor_version >= 6) ||
1058081ff398SHannes Reinecke 	      (enquiry2->fw.major_version == 4 &&
1059081ff398SHannes Reinecke 	       enquiry2->fw.minor_version >= 6) ||
1060081ff398SHannes Reinecke 	      (enquiry2->fw.major_version == 3 &&
1061081ff398SHannes Reinecke 	       enquiry2->fw.minor_version >= 51) ||
1062081ff398SHannes Reinecke 	      (enquiry2->fw.major_version == 2 &&
1063081ff398SHannes Reinecke 	       strcmp(cb->fw_version, FIRMWARE_27X) >= 0))) {
1064081ff398SHannes Reinecke 		shost_printk(KERN_WARNING, cb->host,
1065081ff398SHannes Reinecke 			"Firmware Version '%s' unsupported\n",
1066081ff398SHannes Reinecke 			cb->fw_version);
1067081ff398SHannes Reinecke 		goto out;
1068081ff398SHannes Reinecke 	}
1069081ff398SHannes Reinecke 	/*
1070081ff398SHannes Reinecke 	 * Initialize the Channels, Targets, Memory Size, and SAF-TE
1071081ff398SHannes Reinecke 	 * Enclosure Management Enabled fields.
1072081ff398SHannes Reinecke 	 */
1073081ff398SHannes Reinecke 	switch (enquiry2->hw.model) {
1074081ff398SHannes Reinecke 	case MYRB_5_CHANNEL_BOARD:
1075081ff398SHannes Reinecke 		pchan_max = 5;
1076081ff398SHannes Reinecke 		break;
1077081ff398SHannes Reinecke 	case MYRB_3_CHANNEL_BOARD:
1078081ff398SHannes Reinecke 	case MYRB_3_CHANNEL_ASIC_DAC:
1079081ff398SHannes Reinecke 		pchan_max = 3;
1080081ff398SHannes Reinecke 		break;
1081081ff398SHannes Reinecke 	case MYRB_2_CHANNEL_BOARD:
1082081ff398SHannes Reinecke 		pchan_max = 2;
1083081ff398SHannes Reinecke 		break;
1084081ff398SHannes Reinecke 	default:
1085081ff398SHannes Reinecke 		pchan_max = enquiry2->cfg_chan;
1086081ff398SHannes Reinecke 		break;
1087081ff398SHannes Reinecke 	}
1088081ff398SHannes Reinecke 	pchan_cur = enquiry2->cur_chan;
1089081ff398SHannes Reinecke 	if (enquiry2->scsi_cap.bus_width == MYRB_WIDTH_WIDE_32BIT)
1090081ff398SHannes Reinecke 		cb->bus_width = 32;
1091081ff398SHannes Reinecke 	else if (enquiry2->scsi_cap.bus_width == MYRB_WIDTH_WIDE_16BIT)
1092081ff398SHannes Reinecke 		cb->bus_width = 16;
1093081ff398SHannes Reinecke 	else
1094081ff398SHannes Reinecke 		cb->bus_width = 8;
1095081ff398SHannes Reinecke 	cb->ldev_block_size = enquiry2->ldev_block_size;
1096081ff398SHannes Reinecke 	shost->max_channel = pchan_cur;
1097081ff398SHannes Reinecke 	shost->max_id = enquiry2->max_targets;
1098081ff398SHannes Reinecke 	memsize = enquiry2->mem_size >> 20;
1099081ff398SHannes Reinecke 	cb->safte_enabled = (enquiry2->fault_mgmt == MYRB_FAULT_SAFTE);
1100081ff398SHannes Reinecke 	/*
1101081ff398SHannes Reinecke 	 * Initialize the Controller Queue Depth, Driver Queue Depth,
1102081ff398SHannes Reinecke 	 * Logical Drive Count, Maximum Blocks per Command, Controller
1103081ff398SHannes Reinecke 	 * Scatter/Gather Limit, and Driver Scatter/Gather Limit.
1104081ff398SHannes Reinecke 	 * The Driver Queue Depth must be at most one less than the
1105081ff398SHannes Reinecke 	 * Controller Queue Depth to allow for an automatic drive
1106081ff398SHannes Reinecke 	 * rebuild operation.
1107081ff398SHannes Reinecke 	 */
1108081ff398SHannes Reinecke 	shost->can_queue = cb->enquiry->max_tcq;
1109081ff398SHannes Reinecke 	if (shost->can_queue < 3)
1110081ff398SHannes Reinecke 		shost->can_queue = enquiry2->max_cmds;
1111081ff398SHannes Reinecke 	if (shost->can_queue < 3)
1112081ff398SHannes Reinecke 		/* Play safe and disable TCQ */
1113081ff398SHannes Reinecke 		shost->can_queue = 1;
1114081ff398SHannes Reinecke 
1115081ff398SHannes Reinecke 	if (shost->can_queue > MYRB_CMD_MBOX_COUNT - 2)
1116081ff398SHannes Reinecke 		shost->can_queue = MYRB_CMD_MBOX_COUNT - 2;
1117081ff398SHannes Reinecke 	shost->max_sectors = enquiry2->max_sectors;
1118081ff398SHannes Reinecke 	shost->sg_tablesize = enquiry2->max_sge;
1119081ff398SHannes Reinecke 	if (shost->sg_tablesize > MYRB_SCATTER_GATHER_LIMIT)
1120081ff398SHannes Reinecke 		shost->sg_tablesize = MYRB_SCATTER_GATHER_LIMIT;
1121081ff398SHannes Reinecke 	/*
1122081ff398SHannes Reinecke 	 * Initialize the Stripe Size, Segment Size, and Geometry Translation.
1123081ff398SHannes Reinecke 	 */
1124081ff398SHannes Reinecke 	cb->stripe_size = config2->blocks_per_stripe * config2->block_factor
1125081ff398SHannes Reinecke 		>> (10 - MYRB_BLKSIZE_BITS);
1126081ff398SHannes Reinecke 	cb->segment_size = config2->blocks_per_cacheline * config2->block_factor
1127081ff398SHannes Reinecke 		>> (10 - MYRB_BLKSIZE_BITS);
1128081ff398SHannes Reinecke 	/* Assume 255/63 translation */
1129081ff398SHannes Reinecke 	cb->ldev_geom_heads = 255;
1130081ff398SHannes Reinecke 	cb->ldev_geom_sectors = 63;
1131081ff398SHannes Reinecke 	if (config2->drive_geometry) {
1132081ff398SHannes Reinecke 		cb->ldev_geom_heads = 128;
1133081ff398SHannes Reinecke 		cb->ldev_geom_sectors = 32;
1134081ff398SHannes Reinecke 	}
1135081ff398SHannes Reinecke 
1136081ff398SHannes Reinecke 	/*
1137081ff398SHannes Reinecke 	 * Initialize the Background Initialization Status.
1138081ff398SHannes Reinecke 	 */
1139081ff398SHannes Reinecke 	if ((cb->fw_version[0] == '4' &&
1140081ff398SHannes Reinecke 	     strcmp(cb->fw_version, "4.08") >= 0) ||
1141081ff398SHannes Reinecke 	    (cb->fw_version[0] == '5' &&
1142081ff398SHannes Reinecke 	     strcmp(cb->fw_version, "5.08") >= 0)) {
1143081ff398SHannes Reinecke 		cb->bgi_status_supported = true;
1144081ff398SHannes Reinecke 		myrb_bgi_control(cb);
1145081ff398SHannes Reinecke 	}
1146081ff398SHannes Reinecke 	cb->last_rbld_status = MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS;
1147081ff398SHannes Reinecke 	ret = 0;
1148081ff398SHannes Reinecke 
1149081ff398SHannes Reinecke out:
1150081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1151081ff398SHannes Reinecke 		"Configuring %s PCI RAID Controller\n", cb->model_name);
1152081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1153081ff398SHannes Reinecke 		"  Firmware Version: %s, Memory Size: %dMB\n",
1154081ff398SHannes Reinecke 		cb->fw_version, memsize);
1155081ff398SHannes Reinecke 	if (cb->io_addr == 0)
1156081ff398SHannes Reinecke 		shost_printk(KERN_INFO, cb->host,
1157081ff398SHannes Reinecke 			"  I/O Address: n/a, PCI Address: 0x%lX, IRQ Channel: %d\n",
1158081ff398SHannes Reinecke 			(unsigned long)cb->pci_addr, cb->irq);
1159081ff398SHannes Reinecke 	else
1160081ff398SHannes Reinecke 		shost_printk(KERN_INFO, cb->host,
1161081ff398SHannes Reinecke 			"  I/O Address: 0x%lX, PCI Address: 0x%lX, IRQ Channel: %d\n",
1162081ff398SHannes Reinecke 			(unsigned long)cb->io_addr, (unsigned long)cb->pci_addr,
1163081ff398SHannes Reinecke 			cb->irq);
1164081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1165081ff398SHannes Reinecke 		"  Controller Queue Depth: %d, Maximum Blocks per Command: %d\n",
1166081ff398SHannes Reinecke 		cb->host->can_queue, cb->host->max_sectors);
1167081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1168081ff398SHannes Reinecke 		     "  Driver Queue Depth: %d, Scatter/Gather Limit: %d of %d Segments\n",
1169081ff398SHannes Reinecke 		     cb->host->can_queue, cb->host->sg_tablesize,
1170081ff398SHannes Reinecke 		     MYRB_SCATTER_GATHER_LIMIT);
1171081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1172081ff398SHannes Reinecke 		     "  Stripe Size: %dKB, Segment Size: %dKB, BIOS Geometry: %d/%d%s\n",
1173081ff398SHannes Reinecke 		     cb->stripe_size, cb->segment_size,
1174081ff398SHannes Reinecke 		     cb->ldev_geom_heads, cb->ldev_geom_sectors,
1175081ff398SHannes Reinecke 		     cb->safte_enabled ?
1176081ff398SHannes Reinecke 		     "  SAF-TE Enclosure Management Enabled" : "");
1177081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1178081ff398SHannes Reinecke 		     "  Physical: %d/%d channels %d/%d/%d devices\n",
1179081ff398SHannes Reinecke 		     pchan_cur, pchan_max, 0, cb->enquiry->pdev_dead,
1180081ff398SHannes Reinecke 		     cb->host->max_id);
1181081ff398SHannes Reinecke 
1182081ff398SHannes Reinecke 	shost_printk(KERN_INFO, cb->host,
1183081ff398SHannes Reinecke 		     "  Logical: 1/1 channels, %d/%d disks\n",
1184081ff398SHannes Reinecke 		     cb->enquiry->ldev_count, MYRB_MAX_LDEVS);
1185081ff398SHannes Reinecke 
1186081ff398SHannes Reinecke out_free:
1187081ff398SHannes Reinecke 	dma_free_coherent(&pdev->dev, sizeof(struct myrb_enquiry2),
1188081ff398SHannes Reinecke 			  enquiry2, enquiry2_addr);
1189081ff398SHannes Reinecke 	dma_free_coherent(&pdev->dev, sizeof(struct myrb_config2),
1190081ff398SHannes Reinecke 			  config2, config2_addr);
1191081ff398SHannes Reinecke 
1192081ff398SHannes Reinecke 	return ret;
1193081ff398SHannes Reinecke }
1194081ff398SHannes Reinecke 
119512a1b740SLee Jones /*
1196081ff398SHannes Reinecke  * myrb_unmap - unmaps controller structures
1197081ff398SHannes Reinecke  */
myrb_unmap(struct myrb_hba * cb)1198081ff398SHannes Reinecke static void myrb_unmap(struct myrb_hba *cb)
1199081ff398SHannes Reinecke {
1200081ff398SHannes Reinecke 	if (cb->ldev_info_buf) {
1201081ff398SHannes Reinecke 		size_t ldev_info_size = sizeof(struct myrb_ldev_info) *
1202081ff398SHannes Reinecke 			MYRB_MAX_LDEVS;
1203081ff398SHannes Reinecke 		dma_free_coherent(&cb->pdev->dev, ldev_info_size,
1204081ff398SHannes Reinecke 				  cb->ldev_info_buf, cb->ldev_info_addr);
1205081ff398SHannes Reinecke 		cb->ldev_info_buf = NULL;
1206081ff398SHannes Reinecke 	}
1207081ff398SHannes Reinecke 	if (cb->err_table) {
1208081ff398SHannes Reinecke 		size_t err_table_size = sizeof(struct myrb_error_entry) *
1209081ff398SHannes Reinecke 			MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS;
1210081ff398SHannes Reinecke 		dma_free_coherent(&cb->pdev->dev, err_table_size,
1211081ff398SHannes Reinecke 				  cb->err_table, cb->err_table_addr);
1212081ff398SHannes Reinecke 		cb->err_table = NULL;
1213081ff398SHannes Reinecke 	}
1214081ff398SHannes Reinecke 	if (cb->enquiry) {
1215081ff398SHannes Reinecke 		dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_enquiry),
1216081ff398SHannes Reinecke 				  cb->enquiry, cb->enquiry_addr);
1217081ff398SHannes Reinecke 		cb->enquiry = NULL;
1218081ff398SHannes Reinecke 	}
1219081ff398SHannes Reinecke 	if (cb->first_stat_mbox) {
1220081ff398SHannes Reinecke 		dma_free_coherent(&cb->pdev->dev, cb->stat_mbox_size,
1221081ff398SHannes Reinecke 				  cb->first_stat_mbox, cb->stat_mbox_addr);
1222081ff398SHannes Reinecke 		cb->first_stat_mbox = NULL;
1223081ff398SHannes Reinecke 	}
1224081ff398SHannes Reinecke 	if (cb->first_cmd_mbox) {
1225081ff398SHannes Reinecke 		dma_free_coherent(&cb->pdev->dev, cb->cmd_mbox_size,
1226081ff398SHannes Reinecke 				  cb->first_cmd_mbox, cb->cmd_mbox_addr);
1227081ff398SHannes Reinecke 		cb->first_cmd_mbox = NULL;
1228081ff398SHannes Reinecke 	}
1229081ff398SHannes Reinecke }
1230081ff398SHannes Reinecke 
123112a1b740SLee Jones /*
1232081ff398SHannes Reinecke  * myrb_cleanup - cleanup controller structures
1233081ff398SHannes Reinecke  */
myrb_cleanup(struct myrb_hba * cb)1234081ff398SHannes Reinecke static void myrb_cleanup(struct myrb_hba *cb)
1235081ff398SHannes Reinecke {
1236081ff398SHannes Reinecke 	struct pci_dev *pdev = cb->pdev;
1237081ff398SHannes Reinecke 
1238081ff398SHannes Reinecke 	/* Free the memory mailbox, status, and related structures */
1239081ff398SHannes Reinecke 	myrb_unmap(cb);
1240081ff398SHannes Reinecke 
1241081ff398SHannes Reinecke 	if (cb->mmio_base) {
1242f9f0a461SHannes Reinecke 		if (cb->disable_intr)
1243081ff398SHannes Reinecke 			cb->disable_intr(cb->io_base);
1244081ff398SHannes Reinecke 		iounmap(cb->mmio_base);
1245081ff398SHannes Reinecke 	}
1246081ff398SHannes Reinecke 	if (cb->irq)
1247081ff398SHannes Reinecke 		free_irq(cb->irq, cb);
1248081ff398SHannes Reinecke 	if (cb->io_addr)
1249081ff398SHannes Reinecke 		release_region(cb->io_addr, 0x80);
1250081ff398SHannes Reinecke 	pci_set_drvdata(pdev, NULL);
1251081ff398SHannes Reinecke 	pci_disable_device(pdev);
1252081ff398SHannes Reinecke 	scsi_host_put(cb->host);
1253081ff398SHannes Reinecke }
1254081ff398SHannes Reinecke 
myrb_host_reset(struct scsi_cmnd * scmd)1255081ff398SHannes Reinecke static int myrb_host_reset(struct scsi_cmnd *scmd)
1256081ff398SHannes Reinecke {
1257081ff398SHannes Reinecke 	struct Scsi_Host *shost = scmd->device->host;
1258081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
1259081ff398SHannes Reinecke 
1260081ff398SHannes Reinecke 	cb->reset(cb->io_base);
1261081ff398SHannes Reinecke 	return SUCCESS;
1262081ff398SHannes Reinecke }
1263081ff398SHannes Reinecke 
myrb_pthru_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * scmd)1264081ff398SHannes Reinecke static int myrb_pthru_queuecommand(struct Scsi_Host *shost,
1265081ff398SHannes Reinecke 		struct scsi_cmnd *scmd)
1266081ff398SHannes Reinecke {
12672fd8f23aSBart Van Assche 	struct request *rq = scsi_cmd_to_rq(scmd);
1268081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
1269081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd);
1270081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
1271081ff398SHannes Reinecke 	struct myrb_dcdb *dcdb;
1272081ff398SHannes Reinecke 	dma_addr_t dcdb_addr;
1273081ff398SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
1274081ff398SHannes Reinecke 	struct scatterlist *sgl;
1275081ff398SHannes Reinecke 	unsigned long flags;
1276081ff398SHannes Reinecke 	int nsge;
1277081ff398SHannes Reinecke 
1278081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
1279081ff398SHannes Reinecke 	dcdb = dma_pool_alloc(cb->dcdb_pool, GFP_ATOMIC, &dcdb_addr);
1280081ff398SHannes Reinecke 	if (!dcdb)
1281081ff398SHannes Reinecke 		return SCSI_MLQUEUE_HOST_BUSY;
1282081ff398SHannes Reinecke 	nsge = scsi_dma_map(scmd);
1283081ff398SHannes Reinecke 	if (nsge > 1) {
1284081ff398SHannes Reinecke 		dma_pool_free(cb->dcdb_pool, dcdb, dcdb_addr);
1285081ff398SHannes Reinecke 		scmd->result = (DID_ERROR << 16);
12860061e3f5SBart Van Assche 		scsi_done(scmd);
1287081ff398SHannes Reinecke 		return 0;
1288081ff398SHannes Reinecke 	}
1289081ff398SHannes Reinecke 
1290081ff398SHannes Reinecke 	mbox->type3.opcode = MYRB_CMD_DCDB;
12912fd8f23aSBart Van Assche 	mbox->type3.id = rq->tag + 3;
1292081ff398SHannes Reinecke 	mbox->type3.addr = dcdb_addr;
1293081ff398SHannes Reinecke 	dcdb->channel = sdev->channel;
1294081ff398SHannes Reinecke 	dcdb->target = sdev->id;
1295081ff398SHannes Reinecke 	switch (scmd->sc_data_direction) {
1296081ff398SHannes Reinecke 	case DMA_NONE:
1297081ff398SHannes Reinecke 		dcdb->data_xfer = MYRB_DCDB_XFER_NONE;
1298081ff398SHannes Reinecke 		break;
1299081ff398SHannes Reinecke 	case DMA_TO_DEVICE:
1300081ff398SHannes Reinecke 		dcdb->data_xfer = MYRB_DCDB_XFER_SYSTEM_TO_DEVICE;
1301081ff398SHannes Reinecke 		break;
1302081ff398SHannes Reinecke 	case DMA_FROM_DEVICE:
1303081ff398SHannes Reinecke 		dcdb->data_xfer = MYRB_DCDB_XFER_DEVICE_TO_SYSTEM;
1304081ff398SHannes Reinecke 		break;
1305081ff398SHannes Reinecke 	default:
1306081ff398SHannes Reinecke 		dcdb->data_xfer = MYRB_DCDB_XFER_ILLEGAL;
1307081ff398SHannes Reinecke 		break;
1308081ff398SHannes Reinecke 	}
1309081ff398SHannes Reinecke 	dcdb->early_status = false;
13102fd8f23aSBart Van Assche 	if (rq->timeout <= 10)
1311081ff398SHannes Reinecke 		dcdb->timeout = MYRB_DCDB_TMO_10_SECS;
13122fd8f23aSBart Van Assche 	else if (rq->timeout <= 60)
1313081ff398SHannes Reinecke 		dcdb->timeout = MYRB_DCDB_TMO_60_SECS;
13142fd8f23aSBart Van Assche 	else if (rq->timeout <= 600)
1315081ff398SHannes Reinecke 		dcdb->timeout = MYRB_DCDB_TMO_10_MINS;
1316081ff398SHannes Reinecke 	else
1317081ff398SHannes Reinecke 		dcdb->timeout = MYRB_DCDB_TMO_24_HRS;
1318081ff398SHannes Reinecke 	dcdb->no_autosense = false;
1319081ff398SHannes Reinecke 	dcdb->allow_disconnect = true;
1320081ff398SHannes Reinecke 	sgl = scsi_sglist(scmd);
1321081ff398SHannes Reinecke 	dcdb->dma_addr = sg_dma_address(sgl);
1322081ff398SHannes Reinecke 	if (sg_dma_len(sgl) > USHRT_MAX) {
1323081ff398SHannes Reinecke 		dcdb->xfer_len_lo = sg_dma_len(sgl) & 0xffff;
1324081ff398SHannes Reinecke 		dcdb->xfer_len_hi4 = sg_dma_len(sgl) >> 16;
1325081ff398SHannes Reinecke 	} else {
1326081ff398SHannes Reinecke 		dcdb->xfer_len_lo = sg_dma_len(sgl);
1327081ff398SHannes Reinecke 		dcdb->xfer_len_hi4 = 0;
1328081ff398SHannes Reinecke 	}
1329081ff398SHannes Reinecke 	dcdb->cdb_len = scmd->cmd_len;
1330081ff398SHannes Reinecke 	dcdb->sense_len = sizeof(dcdb->sense);
1331081ff398SHannes Reinecke 	memcpy(&dcdb->cdb, scmd->cmnd, scmd->cmd_len);
1332081ff398SHannes Reinecke 
1333081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
1334081ff398SHannes Reinecke 	cb->qcmd(cb, cmd_blk);
1335081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
1336081ff398SHannes Reinecke 	return 0;
1337081ff398SHannes Reinecke }
1338081ff398SHannes Reinecke 
myrb_inquiry(struct myrb_hba * cb,struct scsi_cmnd * scmd)1339081ff398SHannes Reinecke static void myrb_inquiry(struct myrb_hba *cb,
1340081ff398SHannes Reinecke 		struct scsi_cmnd *scmd)
1341081ff398SHannes Reinecke {
1342081ff398SHannes Reinecke 	unsigned char inq[36] = {
1343081ff398SHannes Reinecke 		0x00, 0x00, 0x03, 0x02, 0x20, 0x00, 0x01, 0x00,
1344081ff398SHannes Reinecke 		0x4d, 0x59, 0x4c, 0x45, 0x58, 0x20, 0x20, 0x20,
1345081ff398SHannes Reinecke 		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1346081ff398SHannes Reinecke 		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1347081ff398SHannes Reinecke 		0x20, 0x20, 0x20, 0x20,
1348081ff398SHannes Reinecke 	};
1349081ff398SHannes Reinecke 
1350081ff398SHannes Reinecke 	if (cb->bus_width > 16)
1351081ff398SHannes Reinecke 		inq[7] |= 1 << 6;
1352081ff398SHannes Reinecke 	if (cb->bus_width > 8)
1353081ff398SHannes Reinecke 		inq[7] |= 1 << 5;
1354081ff398SHannes Reinecke 	memcpy(&inq[16], cb->model_name, 16);
1355081ff398SHannes Reinecke 	memcpy(&inq[32], cb->fw_version, 1);
1356081ff398SHannes Reinecke 	memcpy(&inq[33], &cb->fw_version[2], 2);
1357081ff398SHannes Reinecke 	memcpy(&inq[35], &cb->fw_version[7], 1);
1358081ff398SHannes Reinecke 
1359081ff398SHannes Reinecke 	scsi_sg_copy_from_buffer(scmd, (void *)inq, 36);
1360081ff398SHannes Reinecke }
1361081ff398SHannes Reinecke 
1362081ff398SHannes Reinecke static void
myrb_mode_sense(struct myrb_hba * cb,struct scsi_cmnd * scmd,struct myrb_ldev_info * ldev_info)1363081ff398SHannes Reinecke myrb_mode_sense(struct myrb_hba *cb, struct scsi_cmnd *scmd,
1364081ff398SHannes Reinecke 		struct myrb_ldev_info *ldev_info)
1365081ff398SHannes Reinecke {
1366081ff398SHannes Reinecke 	unsigned char modes[32], *mode_pg;
1367081ff398SHannes Reinecke 	bool dbd;
1368081ff398SHannes Reinecke 	size_t mode_len;
1369081ff398SHannes Reinecke 
1370081ff398SHannes Reinecke 	dbd = (scmd->cmnd[1] & 0x08) == 0x08;
1371081ff398SHannes Reinecke 	if (dbd) {
1372081ff398SHannes Reinecke 		mode_len = 24;
1373081ff398SHannes Reinecke 		mode_pg = &modes[4];
1374081ff398SHannes Reinecke 	} else {
1375081ff398SHannes Reinecke 		mode_len = 32;
1376081ff398SHannes Reinecke 		mode_pg = &modes[12];
1377081ff398SHannes Reinecke 	}
1378081ff398SHannes Reinecke 	memset(modes, 0, sizeof(modes));
1379081ff398SHannes Reinecke 	modes[0] = mode_len - 1;
1380081ff398SHannes Reinecke 	if (!dbd) {
1381081ff398SHannes Reinecke 		unsigned char *block_desc = &modes[4];
1382081ff398SHannes Reinecke 
1383081ff398SHannes Reinecke 		modes[3] = 8;
1384081ff398SHannes Reinecke 		put_unaligned_be32(ldev_info->size, &block_desc[0]);
1385081ff398SHannes Reinecke 		put_unaligned_be32(cb->ldev_block_size, &block_desc[5]);
1386081ff398SHannes Reinecke 	}
1387081ff398SHannes Reinecke 	mode_pg[0] = 0x08;
1388081ff398SHannes Reinecke 	mode_pg[1] = 0x12;
1389081ff398SHannes Reinecke 	if (ldev_info->wb_enabled)
1390081ff398SHannes Reinecke 		mode_pg[2] |= 0x04;
1391081ff398SHannes Reinecke 	if (cb->segment_size) {
1392081ff398SHannes Reinecke 		mode_pg[2] |= 0x08;
1393081ff398SHannes Reinecke 		put_unaligned_be16(cb->segment_size, &mode_pg[14]);
1394081ff398SHannes Reinecke 	}
1395081ff398SHannes Reinecke 
1396081ff398SHannes Reinecke 	scsi_sg_copy_from_buffer(scmd, modes, mode_len);
1397081ff398SHannes Reinecke }
1398081ff398SHannes Reinecke 
myrb_request_sense(struct myrb_hba * cb,struct scsi_cmnd * scmd)1399081ff398SHannes Reinecke static void myrb_request_sense(struct myrb_hba *cb,
1400081ff398SHannes Reinecke 		struct scsi_cmnd *scmd)
1401081ff398SHannes Reinecke {
1402f2b1e9c6SHannes Reinecke 	scsi_build_sense(scmd, 0, NO_SENSE, 0, 0);
1403081ff398SHannes Reinecke 	scsi_sg_copy_from_buffer(scmd, scmd->sense_buffer,
1404081ff398SHannes Reinecke 				 SCSI_SENSE_BUFFERSIZE);
1405081ff398SHannes Reinecke }
1406081ff398SHannes Reinecke 
myrb_read_capacity(struct myrb_hba * cb,struct scsi_cmnd * scmd,struct myrb_ldev_info * ldev_info)1407081ff398SHannes Reinecke static void myrb_read_capacity(struct myrb_hba *cb, struct scsi_cmnd *scmd,
1408081ff398SHannes Reinecke 		struct myrb_ldev_info *ldev_info)
1409081ff398SHannes Reinecke {
1410081ff398SHannes Reinecke 	unsigned char data[8];
1411081ff398SHannes Reinecke 
1412081ff398SHannes Reinecke 	dev_dbg(&scmd->device->sdev_gendev,
1413081ff398SHannes Reinecke 		"Capacity %u, blocksize %u\n",
1414081ff398SHannes Reinecke 		ldev_info->size, cb->ldev_block_size);
1415081ff398SHannes Reinecke 	put_unaligned_be32(ldev_info->size - 1, &data[0]);
1416081ff398SHannes Reinecke 	put_unaligned_be32(cb->ldev_block_size, &data[4]);
1417081ff398SHannes Reinecke 	scsi_sg_copy_from_buffer(scmd, data, 8);
1418081ff398SHannes Reinecke }
1419081ff398SHannes Reinecke 
myrb_ldev_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * scmd)1420081ff398SHannes Reinecke static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
1421081ff398SHannes Reinecke 		struct scsi_cmnd *scmd)
1422081ff398SHannes Reinecke {
1423081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
1424081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd);
1425081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
1426081ff398SHannes Reinecke 	struct myrb_ldev_info *ldev_info;
1427081ff398SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
1428081ff398SHannes Reinecke 	struct scatterlist *sgl;
1429081ff398SHannes Reinecke 	unsigned long flags;
1430081ff398SHannes Reinecke 	u64 lba;
1431081ff398SHannes Reinecke 	u32 block_cnt;
1432081ff398SHannes Reinecke 	int nsge;
1433081ff398SHannes Reinecke 
1434081ff398SHannes Reinecke 	ldev_info = sdev->hostdata;
1435081ff398SHannes Reinecke 	if (ldev_info->state != MYRB_DEVICE_ONLINE &&
1436081ff398SHannes Reinecke 	    ldev_info->state != MYRB_DEVICE_WO) {
1437081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev, "ldev %u in state %x, skip\n",
1438081ff398SHannes Reinecke 			sdev->id, ldev_info ? ldev_info->state : 0xff);
1439081ff398SHannes Reinecke 		scmd->result = (DID_BAD_TARGET << 16);
14400061e3f5SBart Van Assche 		scsi_done(scmd);
1441081ff398SHannes Reinecke 		return 0;
1442081ff398SHannes Reinecke 	}
1443081ff398SHannes Reinecke 	switch (scmd->cmnd[0]) {
1444081ff398SHannes Reinecke 	case TEST_UNIT_READY:
1445081ff398SHannes Reinecke 		scmd->result = (DID_OK << 16);
14460061e3f5SBart Van Assche 		scsi_done(scmd);
1447081ff398SHannes Reinecke 		return 0;
1448081ff398SHannes Reinecke 	case INQUIRY:
1449081ff398SHannes Reinecke 		if (scmd->cmnd[1] & 1) {
1450081ff398SHannes Reinecke 			/* Illegal request, invalid field in CDB */
1451f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
1452081ff398SHannes Reinecke 		} else {
1453081ff398SHannes Reinecke 			myrb_inquiry(cb, scmd);
1454081ff398SHannes Reinecke 			scmd->result = (DID_OK << 16);
1455081ff398SHannes Reinecke 		}
14560061e3f5SBart Van Assche 		scsi_done(scmd);
1457081ff398SHannes Reinecke 		return 0;
1458081ff398SHannes Reinecke 	case SYNCHRONIZE_CACHE:
1459081ff398SHannes Reinecke 		scmd->result = (DID_OK << 16);
14600061e3f5SBart Van Assche 		scsi_done(scmd);
1461081ff398SHannes Reinecke 		return 0;
1462081ff398SHannes Reinecke 	case MODE_SENSE:
1463081ff398SHannes Reinecke 		if ((scmd->cmnd[2] & 0x3F) != 0x3F &&
1464081ff398SHannes Reinecke 		    (scmd->cmnd[2] & 0x3F) != 0x08) {
1465081ff398SHannes Reinecke 			/* Illegal request, invalid field in CDB */
1466f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
1467081ff398SHannes Reinecke 		} else {
1468081ff398SHannes Reinecke 			myrb_mode_sense(cb, scmd, ldev_info);
1469081ff398SHannes Reinecke 			scmd->result = (DID_OK << 16);
1470081ff398SHannes Reinecke 		}
14710061e3f5SBart Van Assche 		scsi_done(scmd);
1472081ff398SHannes Reinecke 		return 0;
1473081ff398SHannes Reinecke 	case READ_CAPACITY:
1474081ff398SHannes Reinecke 		if ((scmd->cmnd[1] & 1) ||
1475081ff398SHannes Reinecke 		    (scmd->cmnd[8] & 1)) {
1476081ff398SHannes Reinecke 			/* Illegal request, invalid field in CDB */
1477f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
14780061e3f5SBart Van Assche 			scsi_done(scmd);
1479081ff398SHannes Reinecke 			return 0;
1480081ff398SHannes Reinecke 		}
1481081ff398SHannes Reinecke 		lba = get_unaligned_be32(&scmd->cmnd[2]);
1482081ff398SHannes Reinecke 		if (lba) {
1483081ff398SHannes Reinecke 			/* Illegal request, invalid field in CDB */
1484f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
14850061e3f5SBart Van Assche 			scsi_done(scmd);
1486081ff398SHannes Reinecke 			return 0;
1487081ff398SHannes Reinecke 		}
1488081ff398SHannes Reinecke 		myrb_read_capacity(cb, scmd, ldev_info);
14890061e3f5SBart Van Assche 		scsi_done(scmd);
1490081ff398SHannes Reinecke 		return 0;
1491081ff398SHannes Reinecke 	case REQUEST_SENSE:
1492081ff398SHannes Reinecke 		myrb_request_sense(cb, scmd);
1493081ff398SHannes Reinecke 		scmd->result = (DID_OK << 16);
1494081ff398SHannes Reinecke 		return 0;
1495081ff398SHannes Reinecke 	case SEND_DIAGNOSTIC:
1496081ff398SHannes Reinecke 		if (scmd->cmnd[1] != 0x04) {
1497081ff398SHannes Reinecke 			/* Illegal request, invalid field in CDB */
1498f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
1499081ff398SHannes Reinecke 		} else {
1500081ff398SHannes Reinecke 			/* Assume good status */
1501081ff398SHannes Reinecke 			scmd->result = (DID_OK << 16);
1502081ff398SHannes Reinecke 		}
15030061e3f5SBart Van Assche 		scsi_done(scmd);
1504081ff398SHannes Reinecke 		return 0;
1505081ff398SHannes Reinecke 	case READ_6:
1506081ff398SHannes Reinecke 		if (ldev_info->state == MYRB_DEVICE_WO) {
1507081ff398SHannes Reinecke 			/* Data protect, attempt to read invalid data */
1508f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, DATA_PROTECT, 0x21, 0x06);
15090061e3f5SBart Van Assche 			scsi_done(scmd);
1510081ff398SHannes Reinecke 			return 0;
1511081ff398SHannes Reinecke 		}
1512df561f66SGustavo A. R. Silva 		fallthrough;
1513081ff398SHannes Reinecke 	case WRITE_6:
1514081ff398SHannes Reinecke 		lba = (((scmd->cmnd[1] & 0x1F) << 16) |
1515081ff398SHannes Reinecke 		       (scmd->cmnd[2] << 8) |
1516081ff398SHannes Reinecke 		       scmd->cmnd[3]);
1517081ff398SHannes Reinecke 		block_cnt = scmd->cmnd[4];
1518081ff398SHannes Reinecke 		break;
1519081ff398SHannes Reinecke 	case READ_10:
1520081ff398SHannes Reinecke 		if (ldev_info->state == MYRB_DEVICE_WO) {
1521081ff398SHannes Reinecke 			/* Data protect, attempt to read invalid data */
1522f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, DATA_PROTECT, 0x21, 0x06);
15230061e3f5SBart Van Assche 			scsi_done(scmd);
1524081ff398SHannes Reinecke 			return 0;
1525081ff398SHannes Reinecke 		}
1526df561f66SGustavo A. R. Silva 		fallthrough;
1527081ff398SHannes Reinecke 	case WRITE_10:
1528081ff398SHannes Reinecke 	case VERIFY:		/* 0x2F */
1529081ff398SHannes Reinecke 	case WRITE_VERIFY:	/* 0x2E */
1530081ff398SHannes Reinecke 		lba = get_unaligned_be32(&scmd->cmnd[2]);
1531081ff398SHannes Reinecke 		block_cnt = get_unaligned_be16(&scmd->cmnd[7]);
1532081ff398SHannes Reinecke 		break;
1533081ff398SHannes Reinecke 	case READ_12:
1534081ff398SHannes Reinecke 		if (ldev_info->state == MYRB_DEVICE_WO) {
1535081ff398SHannes Reinecke 			/* Data protect, attempt to read invalid data */
1536f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, DATA_PROTECT, 0x21, 0x06);
15370061e3f5SBart Van Assche 			scsi_done(scmd);
1538081ff398SHannes Reinecke 			return 0;
1539081ff398SHannes Reinecke 		}
1540df561f66SGustavo A. R. Silva 		fallthrough;
1541081ff398SHannes Reinecke 	case WRITE_12:
1542081ff398SHannes Reinecke 	case VERIFY_12: /* 0xAF */
1543081ff398SHannes Reinecke 	case WRITE_VERIFY_12:	/* 0xAE */
1544081ff398SHannes Reinecke 		lba = get_unaligned_be32(&scmd->cmnd[2]);
1545081ff398SHannes Reinecke 		block_cnt = get_unaligned_be32(&scmd->cmnd[6]);
1546081ff398SHannes Reinecke 		break;
1547081ff398SHannes Reinecke 	default:
1548081ff398SHannes Reinecke 		/* Illegal request, invalid opcode */
1549f2b1e9c6SHannes Reinecke 		scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x20, 0);
15500061e3f5SBart Van Assche 		scsi_done(scmd);
1551081ff398SHannes Reinecke 		return 0;
1552081ff398SHannes Reinecke 	}
1553081ff398SHannes Reinecke 
1554081ff398SHannes Reinecke 	myrb_reset_cmd(cmd_blk);
15552fd8f23aSBart Van Assche 	mbox->type5.id = scsi_cmd_to_rq(scmd)->tag + 3;
1556081ff398SHannes Reinecke 	if (scmd->sc_data_direction == DMA_NONE)
1557081ff398SHannes Reinecke 		goto submit;
1558081ff398SHannes Reinecke 	nsge = scsi_dma_map(scmd);
1559081ff398SHannes Reinecke 	if (nsge == 1) {
1560081ff398SHannes Reinecke 		sgl = scsi_sglist(scmd);
1561081ff398SHannes Reinecke 		if (scmd->sc_data_direction == DMA_FROM_DEVICE)
1562081ff398SHannes Reinecke 			mbox->type5.opcode = MYRB_CMD_READ;
1563081ff398SHannes Reinecke 		else
1564081ff398SHannes Reinecke 			mbox->type5.opcode = MYRB_CMD_WRITE;
1565081ff398SHannes Reinecke 
1566081ff398SHannes Reinecke 		mbox->type5.ld.xfer_len = block_cnt;
1567081ff398SHannes Reinecke 		mbox->type5.ld.ldev_num = sdev->id;
1568081ff398SHannes Reinecke 		mbox->type5.lba = lba;
1569081ff398SHannes Reinecke 		mbox->type5.addr = (u32)sg_dma_address(sgl);
1570081ff398SHannes Reinecke 	} else {
1571081ff398SHannes Reinecke 		struct myrb_sge *hw_sgl;
1572081ff398SHannes Reinecke 		dma_addr_t hw_sgl_addr;
1573081ff398SHannes Reinecke 		int i;
1574081ff398SHannes Reinecke 
1575081ff398SHannes Reinecke 		hw_sgl = dma_pool_alloc(cb->sg_pool, GFP_ATOMIC, &hw_sgl_addr);
1576081ff398SHannes Reinecke 		if (!hw_sgl)
1577081ff398SHannes Reinecke 			return SCSI_MLQUEUE_HOST_BUSY;
1578081ff398SHannes Reinecke 
1579081ff398SHannes Reinecke 		cmd_blk->sgl = hw_sgl;
1580081ff398SHannes Reinecke 		cmd_blk->sgl_addr = hw_sgl_addr;
1581081ff398SHannes Reinecke 
1582081ff398SHannes Reinecke 		if (scmd->sc_data_direction == DMA_FROM_DEVICE)
1583081ff398SHannes Reinecke 			mbox->type5.opcode = MYRB_CMD_READ_SG;
1584081ff398SHannes Reinecke 		else
1585081ff398SHannes Reinecke 			mbox->type5.opcode = MYRB_CMD_WRITE_SG;
1586081ff398SHannes Reinecke 
1587081ff398SHannes Reinecke 		mbox->type5.ld.xfer_len = block_cnt;
1588081ff398SHannes Reinecke 		mbox->type5.ld.ldev_num = sdev->id;
1589081ff398SHannes Reinecke 		mbox->type5.lba = lba;
1590081ff398SHannes Reinecke 		mbox->type5.addr = hw_sgl_addr;
1591081ff398SHannes Reinecke 		mbox->type5.sg_count = nsge;
1592081ff398SHannes Reinecke 
1593081ff398SHannes Reinecke 		scsi_for_each_sg(scmd, sgl, nsge, i) {
1594081ff398SHannes Reinecke 			hw_sgl->sge_addr = (u32)sg_dma_address(sgl);
1595081ff398SHannes Reinecke 			hw_sgl->sge_count = (u32)sg_dma_len(sgl);
1596081ff398SHannes Reinecke 			hw_sgl++;
1597081ff398SHannes Reinecke 		}
1598081ff398SHannes Reinecke 	}
1599081ff398SHannes Reinecke submit:
1600081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
1601081ff398SHannes Reinecke 	cb->qcmd(cb, cmd_blk);
1602081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
1603081ff398SHannes Reinecke 
1604081ff398SHannes Reinecke 	return 0;
1605081ff398SHannes Reinecke }
1606081ff398SHannes Reinecke 
myrb_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * scmd)1607081ff398SHannes Reinecke static int myrb_queuecommand(struct Scsi_Host *shost,
1608081ff398SHannes Reinecke 		struct scsi_cmnd *scmd)
1609081ff398SHannes Reinecke {
1610081ff398SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
1611081ff398SHannes Reinecke 
1612081ff398SHannes Reinecke 	if (sdev->channel > myrb_logical_channel(shost)) {
1613081ff398SHannes Reinecke 		scmd->result = (DID_BAD_TARGET << 16);
16140061e3f5SBart Van Assche 		scsi_done(scmd);
1615081ff398SHannes Reinecke 		return 0;
1616081ff398SHannes Reinecke 	}
1617081ff398SHannes Reinecke 	if (sdev->channel == myrb_logical_channel(shost))
1618081ff398SHannes Reinecke 		return myrb_ldev_queuecommand(shost, scmd);
1619081ff398SHannes Reinecke 
1620081ff398SHannes Reinecke 	return myrb_pthru_queuecommand(shost, scmd);
1621081ff398SHannes Reinecke }
1622081ff398SHannes Reinecke 
myrb_ldev_slave_alloc(struct scsi_device * sdev)1623081ff398SHannes Reinecke static int myrb_ldev_slave_alloc(struct scsi_device *sdev)
1624081ff398SHannes Reinecke {
1625081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1626081ff398SHannes Reinecke 	struct myrb_ldev_info *ldev_info;
1627081ff398SHannes Reinecke 	unsigned short ldev_num = sdev->id;
1628081ff398SHannes Reinecke 	enum raid_level level;
1629081ff398SHannes Reinecke 
1630081ff398SHannes Reinecke 	ldev_info = cb->ldev_info_buf + ldev_num;
1631081ff398SHannes Reinecke 	if (!ldev_info)
1632081ff398SHannes Reinecke 		return -ENXIO;
1633081ff398SHannes Reinecke 
1634081ff398SHannes Reinecke 	sdev->hostdata = kzalloc(sizeof(*ldev_info), GFP_KERNEL);
1635081ff398SHannes Reinecke 	if (!sdev->hostdata)
1636081ff398SHannes Reinecke 		return -ENOMEM;
1637081ff398SHannes Reinecke 	dev_dbg(&sdev->sdev_gendev,
1638081ff398SHannes Reinecke 		"slave alloc ldev %d state %x\n",
1639081ff398SHannes Reinecke 		ldev_num, ldev_info->state);
1640081ff398SHannes Reinecke 	memcpy(sdev->hostdata, ldev_info,
1641081ff398SHannes Reinecke 	       sizeof(*ldev_info));
1642081ff398SHannes Reinecke 	switch (ldev_info->raid_level) {
1643081ff398SHannes Reinecke 	case MYRB_RAID_LEVEL0:
1644081ff398SHannes Reinecke 		level = RAID_LEVEL_LINEAR;
1645081ff398SHannes Reinecke 		break;
1646081ff398SHannes Reinecke 	case MYRB_RAID_LEVEL1:
1647081ff398SHannes Reinecke 		level = RAID_LEVEL_1;
1648081ff398SHannes Reinecke 		break;
1649081ff398SHannes Reinecke 	case MYRB_RAID_LEVEL3:
1650081ff398SHannes Reinecke 		level = RAID_LEVEL_3;
1651081ff398SHannes Reinecke 		break;
1652081ff398SHannes Reinecke 	case MYRB_RAID_LEVEL5:
1653081ff398SHannes Reinecke 		level = RAID_LEVEL_5;
1654081ff398SHannes Reinecke 		break;
1655081ff398SHannes Reinecke 	case MYRB_RAID_LEVEL6:
1656081ff398SHannes Reinecke 		level = RAID_LEVEL_6;
1657081ff398SHannes Reinecke 		break;
1658081ff398SHannes Reinecke 	case MYRB_RAID_JBOD:
1659081ff398SHannes Reinecke 		level = RAID_LEVEL_JBOD;
1660081ff398SHannes Reinecke 		break;
1661081ff398SHannes Reinecke 	default:
1662081ff398SHannes Reinecke 		level = RAID_LEVEL_UNKNOWN;
1663081ff398SHannes Reinecke 		break;
1664081ff398SHannes Reinecke 	}
1665081ff398SHannes Reinecke 	raid_set_level(myrb_raid_template, &sdev->sdev_gendev, level);
1666081ff398SHannes Reinecke 	return 0;
1667081ff398SHannes Reinecke }
1668081ff398SHannes Reinecke 
myrb_pdev_slave_alloc(struct scsi_device * sdev)1669081ff398SHannes Reinecke static int myrb_pdev_slave_alloc(struct scsi_device *sdev)
1670081ff398SHannes Reinecke {
1671081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1672081ff398SHannes Reinecke 	struct myrb_pdev_state *pdev_info;
1673081ff398SHannes Reinecke 	unsigned short status;
1674081ff398SHannes Reinecke 
1675081ff398SHannes Reinecke 	if (sdev->id > MYRB_MAX_TARGETS)
1676081ff398SHannes Reinecke 		return -ENXIO;
1677081ff398SHannes Reinecke 
167827363ba8SChristoph Hellwig 	pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL);
1679081ff398SHannes Reinecke 	if (!pdev_info)
1680081ff398SHannes Reinecke 		return -ENOMEM;
1681081ff398SHannes Reinecke 
1682081ff398SHannes Reinecke 	status = myrb_exec_type3D(cb, MYRB_CMD_GET_DEVICE_STATE,
1683081ff398SHannes Reinecke 				  sdev, pdev_info);
1684081ff398SHannes Reinecke 	if (status != MYRB_STATUS_SUCCESS) {
1685081ff398SHannes Reinecke 		dev_dbg(&sdev->sdev_gendev,
1686081ff398SHannes Reinecke 			"Failed to get device state, status %x\n",
1687081ff398SHannes Reinecke 			status);
1688081ff398SHannes Reinecke 		kfree(pdev_info);
1689081ff398SHannes Reinecke 		return -ENXIO;
1690081ff398SHannes Reinecke 	}
1691081ff398SHannes Reinecke 	if (!pdev_info->present) {
1692081ff398SHannes Reinecke 		dev_dbg(&sdev->sdev_gendev,
1693081ff398SHannes Reinecke 			"device not present, skip\n");
1694081ff398SHannes Reinecke 		kfree(pdev_info);
1695081ff398SHannes Reinecke 		return -ENXIO;
1696081ff398SHannes Reinecke 	}
1697081ff398SHannes Reinecke 	dev_dbg(&sdev->sdev_gendev,
1698081ff398SHannes Reinecke 		"slave alloc pdev %d:%d state %x\n",
1699081ff398SHannes Reinecke 		sdev->channel, sdev->id, pdev_info->state);
1700081ff398SHannes Reinecke 	sdev->hostdata = pdev_info;
1701081ff398SHannes Reinecke 
1702081ff398SHannes Reinecke 	return 0;
1703081ff398SHannes Reinecke }
1704081ff398SHannes Reinecke 
myrb_slave_alloc(struct scsi_device * sdev)1705081ff398SHannes Reinecke static int myrb_slave_alloc(struct scsi_device *sdev)
1706081ff398SHannes Reinecke {
1707081ff398SHannes Reinecke 	if (sdev->channel > myrb_logical_channel(sdev->host))
1708081ff398SHannes Reinecke 		return -ENXIO;
1709081ff398SHannes Reinecke 
1710081ff398SHannes Reinecke 	if (sdev->lun > 0)
1711081ff398SHannes Reinecke 		return -ENXIO;
1712081ff398SHannes Reinecke 
1713081ff398SHannes Reinecke 	if (sdev->channel == myrb_logical_channel(sdev->host))
1714081ff398SHannes Reinecke 		return myrb_ldev_slave_alloc(sdev);
1715081ff398SHannes Reinecke 
1716081ff398SHannes Reinecke 	return myrb_pdev_slave_alloc(sdev);
1717081ff398SHannes Reinecke }
1718081ff398SHannes Reinecke 
myrb_slave_configure(struct scsi_device * sdev)1719081ff398SHannes Reinecke static int myrb_slave_configure(struct scsi_device *sdev)
1720081ff398SHannes Reinecke {
1721081ff398SHannes Reinecke 	struct myrb_ldev_info *ldev_info;
1722081ff398SHannes Reinecke 
1723081ff398SHannes Reinecke 	if (sdev->channel > myrb_logical_channel(sdev->host))
1724081ff398SHannes Reinecke 		return -ENXIO;
1725081ff398SHannes Reinecke 
1726081ff398SHannes Reinecke 	if (sdev->channel < myrb_logical_channel(sdev->host)) {
1727081ff398SHannes Reinecke 		sdev->no_uld_attach = 1;
1728081ff398SHannes Reinecke 		return 0;
1729081ff398SHannes Reinecke 	}
1730081ff398SHannes Reinecke 	if (sdev->lun != 0)
1731081ff398SHannes Reinecke 		return -ENXIO;
1732081ff398SHannes Reinecke 
1733081ff398SHannes Reinecke 	ldev_info = sdev->hostdata;
1734081ff398SHannes Reinecke 	if (!ldev_info)
1735081ff398SHannes Reinecke 		return -ENXIO;
1736081ff398SHannes Reinecke 	if (ldev_info->state != MYRB_DEVICE_ONLINE)
1737081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1738081ff398SHannes Reinecke 			    "Logical drive is %s\n",
1739081ff398SHannes Reinecke 			    myrb_devstate_name(ldev_info->state));
1740081ff398SHannes Reinecke 
1741081ff398SHannes Reinecke 	sdev->tagged_supported = 1;
1742081ff398SHannes Reinecke 	return 0;
1743081ff398SHannes Reinecke }
1744081ff398SHannes Reinecke 
myrb_slave_destroy(struct scsi_device * sdev)1745081ff398SHannes Reinecke static void myrb_slave_destroy(struct scsi_device *sdev)
1746081ff398SHannes Reinecke {
1747081ff398SHannes Reinecke 	kfree(sdev->hostdata);
1748081ff398SHannes Reinecke }
1749081ff398SHannes Reinecke 
myrb_biosparam(struct scsi_device * sdev,struct block_device * bdev,sector_t capacity,int geom[])1750081ff398SHannes Reinecke static int myrb_biosparam(struct scsi_device *sdev, struct block_device *bdev,
1751081ff398SHannes Reinecke 		sector_t capacity, int geom[])
1752081ff398SHannes Reinecke {
1753081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1754081ff398SHannes Reinecke 
1755081ff398SHannes Reinecke 	geom[0] = cb->ldev_geom_heads;
1756081ff398SHannes Reinecke 	geom[1] = cb->ldev_geom_sectors;
1757081ff398SHannes Reinecke 	geom[2] = sector_div(capacity, geom[0] * geom[1]);
1758081ff398SHannes Reinecke 
1759081ff398SHannes Reinecke 	return 0;
1760081ff398SHannes Reinecke }
1761081ff398SHannes Reinecke 
raid_state_show(struct device * dev,struct device_attribute * attr,char * buf)1762081ff398SHannes Reinecke static ssize_t raid_state_show(struct device *dev,
1763081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
1764081ff398SHannes Reinecke {
1765081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
1766081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1767081ff398SHannes Reinecke 	int ret;
1768081ff398SHannes Reinecke 
1769081ff398SHannes Reinecke 	if (!sdev->hostdata)
1770081ff398SHannes Reinecke 		return snprintf(buf, 16, "Unknown\n");
1771081ff398SHannes Reinecke 
1772081ff398SHannes Reinecke 	if (sdev->channel == myrb_logical_channel(sdev->host)) {
1773081ff398SHannes Reinecke 		struct myrb_ldev_info *ldev_info = sdev->hostdata;
1774081ff398SHannes Reinecke 		const char *name;
1775081ff398SHannes Reinecke 
1776081ff398SHannes Reinecke 		name = myrb_devstate_name(ldev_info->state);
1777081ff398SHannes Reinecke 		if (name)
1778*56de23eaSArnd Bergmann 			ret = snprintf(buf, 64, "%s\n", name);
1779081ff398SHannes Reinecke 		else
1780*56de23eaSArnd Bergmann 			ret = snprintf(buf, 64, "Invalid (%02X)\n",
1781081ff398SHannes Reinecke 				       ldev_info->state);
1782081ff398SHannes Reinecke 	} else {
1783081ff398SHannes Reinecke 		struct myrb_pdev_state *pdev_info = sdev->hostdata;
1784081ff398SHannes Reinecke 		unsigned short status;
1785081ff398SHannes Reinecke 		const char *name;
1786081ff398SHannes Reinecke 
1787081ff398SHannes Reinecke 		status = myrb_exec_type3D(cb, MYRB_CMD_GET_DEVICE_STATE,
1788081ff398SHannes Reinecke 					  sdev, pdev_info);
1789081ff398SHannes Reinecke 		if (status != MYRB_STATUS_SUCCESS)
1790081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1791081ff398SHannes Reinecke 				    "Failed to get device state, status %x\n",
1792081ff398SHannes Reinecke 				    status);
1793081ff398SHannes Reinecke 
1794081ff398SHannes Reinecke 		if (!pdev_info->present)
1795081ff398SHannes Reinecke 			name = "Removed";
1796081ff398SHannes Reinecke 		else
1797081ff398SHannes Reinecke 			name = myrb_devstate_name(pdev_info->state);
1798081ff398SHannes Reinecke 		if (name)
1799*56de23eaSArnd Bergmann 			ret = snprintf(buf, 64, "%s\n", name);
1800081ff398SHannes Reinecke 		else
1801*56de23eaSArnd Bergmann 			ret = snprintf(buf, 64, "Invalid (%02X)\n",
1802081ff398SHannes Reinecke 				       pdev_info->state);
1803081ff398SHannes Reinecke 	}
1804081ff398SHannes Reinecke 	return ret;
1805081ff398SHannes Reinecke }
1806081ff398SHannes Reinecke 
raid_state_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1807081ff398SHannes Reinecke static ssize_t raid_state_store(struct device *dev,
1808081ff398SHannes Reinecke 		struct device_attribute *attr, const char *buf, size_t count)
1809081ff398SHannes Reinecke {
1810081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
1811081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1812081ff398SHannes Reinecke 	struct myrb_pdev_state *pdev_info;
1813081ff398SHannes Reinecke 	enum myrb_devstate new_state;
1814081ff398SHannes Reinecke 	unsigned short status;
1815081ff398SHannes Reinecke 
1816081ff398SHannes Reinecke 	if (!strncmp(buf, "kill", 4) ||
1817081ff398SHannes Reinecke 	    !strncmp(buf, "offline", 7))
1818081ff398SHannes Reinecke 		new_state = MYRB_DEVICE_DEAD;
1819081ff398SHannes Reinecke 	else if (!strncmp(buf, "online", 6))
1820081ff398SHannes Reinecke 		new_state = MYRB_DEVICE_ONLINE;
1821081ff398SHannes Reinecke 	else if (!strncmp(buf, "standby", 7))
1822081ff398SHannes Reinecke 		new_state = MYRB_DEVICE_STANDBY;
1823081ff398SHannes Reinecke 	else
1824081ff398SHannes Reinecke 		return -EINVAL;
1825081ff398SHannes Reinecke 
1826081ff398SHannes Reinecke 	pdev_info = sdev->hostdata;
1827081ff398SHannes Reinecke 	if (!pdev_info) {
1828081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1829081ff398SHannes Reinecke 			    "Failed - no physical device information\n");
1830081ff398SHannes Reinecke 		return -ENXIO;
1831081ff398SHannes Reinecke 	}
1832081ff398SHannes Reinecke 	if (!pdev_info->present) {
1833081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1834081ff398SHannes Reinecke 			    "Failed - device not present\n");
1835081ff398SHannes Reinecke 		return -ENXIO;
1836081ff398SHannes Reinecke 	}
1837081ff398SHannes Reinecke 
1838081ff398SHannes Reinecke 	if (pdev_info->state == new_state)
1839081ff398SHannes Reinecke 		return count;
1840081ff398SHannes Reinecke 
1841081ff398SHannes Reinecke 	status = myrb_set_pdev_state(cb, sdev, new_state);
1842081ff398SHannes Reinecke 	switch (status) {
1843081ff398SHannes Reinecke 	case MYRB_STATUS_SUCCESS:
1844081ff398SHannes Reinecke 		break;
1845081ff398SHannes Reinecke 	case MYRB_STATUS_START_DEVICE_FAILED:
1846081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1847081ff398SHannes Reinecke 			     "Failed - Unable to Start Device\n");
1848081ff398SHannes Reinecke 		count = -EAGAIN;
1849081ff398SHannes Reinecke 		break;
1850081ff398SHannes Reinecke 	case MYRB_STATUS_NO_DEVICE:
1851081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1852081ff398SHannes Reinecke 			    "Failed - No Device at Address\n");
1853081ff398SHannes Reinecke 		count = -ENODEV;
1854081ff398SHannes Reinecke 		break;
1855081ff398SHannes Reinecke 	case MYRB_STATUS_INVALID_CHANNEL_OR_TARGET:
1856081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1857081ff398SHannes Reinecke 			 "Failed - Invalid Channel or Target or Modifier\n");
1858081ff398SHannes Reinecke 		count = -EINVAL;
1859081ff398SHannes Reinecke 		break;
1860081ff398SHannes Reinecke 	case MYRB_STATUS_CHANNEL_BUSY:
1861081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1862081ff398SHannes Reinecke 			 "Failed - Channel Busy\n");
1863081ff398SHannes Reinecke 		count = -EBUSY;
1864081ff398SHannes Reinecke 		break;
1865081ff398SHannes Reinecke 	default:
1866081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1867081ff398SHannes Reinecke 			 "Failed - Unexpected Status %04X\n", status);
1868081ff398SHannes Reinecke 		count = -EIO;
1869081ff398SHannes Reinecke 		break;
1870081ff398SHannes Reinecke 	}
1871081ff398SHannes Reinecke 	return count;
1872081ff398SHannes Reinecke }
1873081ff398SHannes Reinecke static DEVICE_ATTR_RW(raid_state);
1874081ff398SHannes Reinecke 
raid_level_show(struct device * dev,struct device_attribute * attr,char * buf)1875081ff398SHannes Reinecke static ssize_t raid_level_show(struct device *dev,
1876081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
1877081ff398SHannes Reinecke {
1878081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
1879081ff398SHannes Reinecke 
1880081ff398SHannes Reinecke 	if (sdev->channel == myrb_logical_channel(sdev->host)) {
1881081ff398SHannes Reinecke 		struct myrb_ldev_info *ldev_info = sdev->hostdata;
1882081ff398SHannes Reinecke 		const char *name;
1883081ff398SHannes Reinecke 
1884081ff398SHannes Reinecke 		if (!ldev_info)
1885081ff398SHannes Reinecke 			return -ENXIO;
1886081ff398SHannes Reinecke 
1887081ff398SHannes Reinecke 		name = myrb_raidlevel_name(ldev_info->raid_level);
1888081ff398SHannes Reinecke 		if (!name)
1889*56de23eaSArnd Bergmann 			return snprintf(buf, 64, "Invalid (%02X)\n",
1890081ff398SHannes Reinecke 					ldev_info->state);
1891*56de23eaSArnd Bergmann 		return snprintf(buf, 64, "%s\n", name);
1892081ff398SHannes Reinecke 	}
1893*56de23eaSArnd Bergmann 	return snprintf(buf, 64, "Physical Drive\n");
1894081ff398SHannes Reinecke }
1895081ff398SHannes Reinecke static DEVICE_ATTR_RO(raid_level);
1896081ff398SHannes Reinecke 
rebuild_show(struct device * dev,struct device_attribute * attr,char * buf)1897081ff398SHannes Reinecke static ssize_t rebuild_show(struct device *dev,
1898081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
1899081ff398SHannes Reinecke {
1900081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
1901081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1902081ff398SHannes Reinecke 	struct myrb_rbld_progress rbld_buf;
1903081ff398SHannes Reinecke 	unsigned char status;
1904081ff398SHannes Reinecke 
1905081ff398SHannes Reinecke 	if (sdev->channel < myrb_logical_channel(sdev->host))
1906*56de23eaSArnd Bergmann 		return snprintf(buf, 64, "physical device - not rebuilding\n");
1907081ff398SHannes Reinecke 
1908081ff398SHannes Reinecke 	status = myrb_get_rbld_progress(cb, &rbld_buf);
1909081ff398SHannes Reinecke 
1910081ff398SHannes Reinecke 	if (rbld_buf.ldev_num != sdev->id ||
1911081ff398SHannes Reinecke 	    status != MYRB_STATUS_SUCCESS)
1912*56de23eaSArnd Bergmann 		return snprintf(buf, 64, "not rebuilding\n");
1913081ff398SHannes Reinecke 
1914*56de23eaSArnd Bergmann 	return snprintf(buf, 64, "rebuilding block %u of %u\n",
1915081ff398SHannes Reinecke 			rbld_buf.ldev_size - rbld_buf.blocks_left,
1916081ff398SHannes Reinecke 			rbld_buf.ldev_size);
1917081ff398SHannes Reinecke }
1918081ff398SHannes Reinecke 
rebuild_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1919081ff398SHannes Reinecke static ssize_t rebuild_store(struct device *dev,
1920081ff398SHannes Reinecke 		struct device_attribute *attr, const char *buf, size_t count)
1921081ff398SHannes Reinecke {
1922081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
1923081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
1924081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk;
1925081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox;
1926081ff398SHannes Reinecke 	unsigned short status;
1927081ff398SHannes Reinecke 	int rc, start;
1928081ff398SHannes Reinecke 	const char *msg;
1929081ff398SHannes Reinecke 
1930081ff398SHannes Reinecke 	rc = kstrtoint(buf, 0, &start);
1931081ff398SHannes Reinecke 	if (rc)
1932081ff398SHannes Reinecke 		return rc;
1933081ff398SHannes Reinecke 
1934081ff398SHannes Reinecke 	if (sdev->channel >= myrb_logical_channel(sdev->host))
1935081ff398SHannes Reinecke 		return -ENXIO;
1936081ff398SHannes Reinecke 
1937081ff398SHannes Reinecke 	status = myrb_get_rbld_progress(cb, NULL);
1938081ff398SHannes Reinecke 	if (start) {
1939081ff398SHannes Reinecke 		if (status == MYRB_STATUS_SUCCESS) {
1940081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1941081ff398SHannes Reinecke 				    "Rebuild Not Initiated; already in progress\n");
1942081ff398SHannes Reinecke 			return -EALREADY;
1943081ff398SHannes Reinecke 		}
1944081ff398SHannes Reinecke 		mutex_lock(&cb->dcmd_mutex);
1945081ff398SHannes Reinecke 		cmd_blk = &cb->dcmd_blk;
1946081ff398SHannes Reinecke 		myrb_reset_cmd(cmd_blk);
1947081ff398SHannes Reinecke 		mbox = &cmd_blk->mbox;
1948081ff398SHannes Reinecke 		mbox->type3D.opcode = MYRB_CMD_REBUILD_ASYNC;
1949081ff398SHannes Reinecke 		mbox->type3D.id = MYRB_DCMD_TAG;
1950081ff398SHannes Reinecke 		mbox->type3D.channel = sdev->channel;
1951081ff398SHannes Reinecke 		mbox->type3D.target = sdev->id;
1952081ff398SHannes Reinecke 		status = myrb_exec_cmd(cb, cmd_blk);
1953081ff398SHannes Reinecke 		mutex_unlock(&cb->dcmd_mutex);
1954081ff398SHannes Reinecke 	} else {
1955081ff398SHannes Reinecke 		struct pci_dev *pdev = cb->pdev;
1956081ff398SHannes Reinecke 		unsigned char *rate;
1957081ff398SHannes Reinecke 		dma_addr_t rate_addr;
1958081ff398SHannes Reinecke 
1959081ff398SHannes Reinecke 		if (status != MYRB_STATUS_SUCCESS) {
1960081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1961081ff398SHannes Reinecke 				    "Rebuild Not Cancelled; not in progress\n");
1962081ff398SHannes Reinecke 			return 0;
1963081ff398SHannes Reinecke 		}
1964081ff398SHannes Reinecke 
1965081ff398SHannes Reinecke 		rate = dma_alloc_coherent(&pdev->dev, sizeof(char),
1966081ff398SHannes Reinecke 					  &rate_addr, GFP_KERNEL);
1967081ff398SHannes Reinecke 		if (rate == NULL) {
1968081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1969081ff398SHannes Reinecke 				    "Cancellation of Rebuild Failed - Out of Memory\n");
1970081ff398SHannes Reinecke 			return -ENOMEM;
1971081ff398SHannes Reinecke 		}
1972081ff398SHannes Reinecke 		mutex_lock(&cb->dcmd_mutex);
1973081ff398SHannes Reinecke 		cmd_blk = &cb->dcmd_blk;
1974081ff398SHannes Reinecke 		myrb_reset_cmd(cmd_blk);
1975081ff398SHannes Reinecke 		mbox = &cmd_blk->mbox;
1976081ff398SHannes Reinecke 		mbox->type3R.opcode = MYRB_CMD_REBUILD_CONTROL;
1977081ff398SHannes Reinecke 		mbox->type3R.id = MYRB_DCMD_TAG;
1978081ff398SHannes Reinecke 		mbox->type3R.rbld_rate = 0xFF;
1979081ff398SHannes Reinecke 		mbox->type3R.addr = rate_addr;
1980081ff398SHannes Reinecke 		status = myrb_exec_cmd(cb, cmd_blk);
1981081ff398SHannes Reinecke 		dma_free_coherent(&pdev->dev, sizeof(char), rate, rate_addr);
1982081ff398SHannes Reinecke 		mutex_unlock(&cb->dcmd_mutex);
1983081ff398SHannes Reinecke 	}
1984081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS) {
1985081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev, "Rebuild %s\n",
1986081ff398SHannes Reinecke 			    start ? "Initiated" : "Cancelled");
1987081ff398SHannes Reinecke 		return count;
1988081ff398SHannes Reinecke 	}
1989081ff398SHannes Reinecke 	if (!start) {
1990081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
1991081ff398SHannes Reinecke 			    "Rebuild Not Cancelled, status 0x%x\n",
1992081ff398SHannes Reinecke 			    status);
1993081ff398SHannes Reinecke 		return -EIO;
1994081ff398SHannes Reinecke 	}
1995081ff398SHannes Reinecke 
1996081ff398SHannes Reinecke 	switch (status) {
1997081ff398SHannes Reinecke 	case MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE:
1998081ff398SHannes Reinecke 		msg = "Attempt to Rebuild Online or Unresponsive Drive";
1999081ff398SHannes Reinecke 		break;
2000081ff398SHannes Reinecke 	case MYRB_STATUS_RBLD_NEW_DISK_FAILED:
2001081ff398SHannes Reinecke 		msg = "New Disk Failed During Rebuild";
2002081ff398SHannes Reinecke 		break;
2003081ff398SHannes Reinecke 	case MYRB_STATUS_INVALID_ADDRESS:
2004081ff398SHannes Reinecke 		msg = "Invalid Device Address";
2005081ff398SHannes Reinecke 		break;
2006081ff398SHannes Reinecke 	case MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS:
2007081ff398SHannes Reinecke 		msg = "Already in Progress";
2008081ff398SHannes Reinecke 		break;
2009081ff398SHannes Reinecke 	default:
2010081ff398SHannes Reinecke 		msg = NULL;
2011081ff398SHannes Reinecke 		break;
2012081ff398SHannes Reinecke 	}
2013081ff398SHannes Reinecke 	if (msg)
2014081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
2015081ff398SHannes Reinecke 			    "Rebuild Failed - %s\n", msg);
2016081ff398SHannes Reinecke 	else
2017081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
2018081ff398SHannes Reinecke 			    "Rebuild Failed, status 0x%x\n", status);
2019081ff398SHannes Reinecke 
2020081ff398SHannes Reinecke 	return -EIO;
2021081ff398SHannes Reinecke }
2022081ff398SHannes Reinecke static DEVICE_ATTR_RW(rebuild);
2023081ff398SHannes Reinecke 
consistency_check_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2024081ff398SHannes Reinecke static ssize_t consistency_check_store(struct device *dev,
2025081ff398SHannes Reinecke 		struct device_attribute *attr, const char *buf, size_t count)
2026081ff398SHannes Reinecke {
2027081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
2028081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
2029081ff398SHannes Reinecke 	struct myrb_rbld_progress rbld_buf;
2030081ff398SHannes Reinecke 	struct myrb_cmdblk *cmd_blk;
2031081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox;
2032081ff398SHannes Reinecke 	unsigned short ldev_num = 0xFFFF;
2033081ff398SHannes Reinecke 	unsigned short status;
2034081ff398SHannes Reinecke 	int rc, start;
2035081ff398SHannes Reinecke 	const char *msg;
2036081ff398SHannes Reinecke 
2037081ff398SHannes Reinecke 	rc = kstrtoint(buf, 0, &start);
2038081ff398SHannes Reinecke 	if (rc)
2039081ff398SHannes Reinecke 		return rc;
2040081ff398SHannes Reinecke 
2041081ff398SHannes Reinecke 	if (sdev->channel < myrb_logical_channel(sdev->host))
2042081ff398SHannes Reinecke 		return -ENXIO;
2043081ff398SHannes Reinecke 
2044081ff398SHannes Reinecke 	status = myrb_get_rbld_progress(cb, &rbld_buf);
2045081ff398SHannes Reinecke 	if (start) {
2046081ff398SHannes Reinecke 		if (status == MYRB_STATUS_SUCCESS) {
2047081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
2048081ff398SHannes Reinecke 				    "Check Consistency Not Initiated; already in progress\n");
2049081ff398SHannes Reinecke 			return -EALREADY;
2050081ff398SHannes Reinecke 		}
2051081ff398SHannes Reinecke 		mutex_lock(&cb->dcmd_mutex);
2052081ff398SHannes Reinecke 		cmd_blk = &cb->dcmd_blk;
2053081ff398SHannes Reinecke 		myrb_reset_cmd(cmd_blk);
2054081ff398SHannes Reinecke 		mbox = &cmd_blk->mbox;
2055081ff398SHannes Reinecke 		mbox->type3C.opcode = MYRB_CMD_CHECK_CONSISTENCY_ASYNC;
2056081ff398SHannes Reinecke 		mbox->type3C.id = MYRB_DCMD_TAG;
2057081ff398SHannes Reinecke 		mbox->type3C.ldev_num = sdev->id;
2058081ff398SHannes Reinecke 		mbox->type3C.auto_restore = true;
2059081ff398SHannes Reinecke 
2060081ff398SHannes Reinecke 		status = myrb_exec_cmd(cb, cmd_blk);
2061081ff398SHannes Reinecke 		mutex_unlock(&cb->dcmd_mutex);
2062081ff398SHannes Reinecke 	} else {
2063081ff398SHannes Reinecke 		struct pci_dev *pdev = cb->pdev;
2064081ff398SHannes Reinecke 		unsigned char *rate;
2065081ff398SHannes Reinecke 		dma_addr_t rate_addr;
2066081ff398SHannes Reinecke 
2067081ff398SHannes Reinecke 		if (ldev_num != sdev->id) {
2068081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
2069081ff398SHannes Reinecke 				    "Check Consistency Not Cancelled; not in progress\n");
2070081ff398SHannes Reinecke 			return 0;
2071081ff398SHannes Reinecke 		}
2072081ff398SHannes Reinecke 		rate = dma_alloc_coherent(&pdev->dev, sizeof(char),
2073081ff398SHannes Reinecke 					  &rate_addr, GFP_KERNEL);
2074081ff398SHannes Reinecke 		if (rate == NULL) {
2075081ff398SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
2076081ff398SHannes Reinecke 				    "Cancellation of Check Consistency Failed - Out of Memory\n");
2077081ff398SHannes Reinecke 			return -ENOMEM;
2078081ff398SHannes Reinecke 		}
2079081ff398SHannes Reinecke 		mutex_lock(&cb->dcmd_mutex);
2080081ff398SHannes Reinecke 		cmd_blk = &cb->dcmd_blk;
2081081ff398SHannes Reinecke 		myrb_reset_cmd(cmd_blk);
2082081ff398SHannes Reinecke 		mbox = &cmd_blk->mbox;
2083081ff398SHannes Reinecke 		mbox->type3R.opcode = MYRB_CMD_REBUILD_CONTROL;
2084081ff398SHannes Reinecke 		mbox->type3R.id = MYRB_DCMD_TAG;
2085081ff398SHannes Reinecke 		mbox->type3R.rbld_rate = 0xFF;
2086081ff398SHannes Reinecke 		mbox->type3R.addr = rate_addr;
2087081ff398SHannes Reinecke 		status = myrb_exec_cmd(cb, cmd_blk);
2088081ff398SHannes Reinecke 		dma_free_coherent(&pdev->dev, sizeof(char), rate, rate_addr);
2089081ff398SHannes Reinecke 		mutex_unlock(&cb->dcmd_mutex);
2090081ff398SHannes Reinecke 	}
2091081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS) {
2092081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev, "Check Consistency %s\n",
2093081ff398SHannes Reinecke 			    start ? "Initiated" : "Cancelled");
2094081ff398SHannes Reinecke 		return count;
2095081ff398SHannes Reinecke 	}
2096081ff398SHannes Reinecke 	if (!start) {
2097081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
2098081ff398SHannes Reinecke 			    "Check Consistency Not Cancelled, status 0x%x\n",
2099081ff398SHannes Reinecke 			    status);
2100081ff398SHannes Reinecke 		return -EIO;
2101081ff398SHannes Reinecke 	}
2102081ff398SHannes Reinecke 
2103081ff398SHannes Reinecke 	switch (status) {
2104081ff398SHannes Reinecke 	case MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE:
2105081ff398SHannes Reinecke 		msg = "Dependent Physical Device is DEAD";
2106081ff398SHannes Reinecke 		break;
2107081ff398SHannes Reinecke 	case MYRB_STATUS_RBLD_NEW_DISK_FAILED:
2108081ff398SHannes Reinecke 		msg = "New Disk Failed During Rebuild";
2109081ff398SHannes Reinecke 		break;
2110081ff398SHannes Reinecke 	case MYRB_STATUS_INVALID_ADDRESS:
2111081ff398SHannes Reinecke 		msg = "Invalid or Nonredundant Logical Drive";
2112081ff398SHannes Reinecke 		break;
2113081ff398SHannes Reinecke 	case MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS:
2114081ff398SHannes Reinecke 		msg = "Already in Progress";
2115081ff398SHannes Reinecke 		break;
2116081ff398SHannes Reinecke 	default:
2117081ff398SHannes Reinecke 		msg = NULL;
2118081ff398SHannes Reinecke 		break;
2119081ff398SHannes Reinecke 	}
2120081ff398SHannes Reinecke 	if (msg)
2121081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
2122081ff398SHannes Reinecke 			    "Check Consistency Failed - %s\n", msg);
2123081ff398SHannes Reinecke 	else
2124081ff398SHannes Reinecke 		sdev_printk(KERN_INFO, sdev,
2125081ff398SHannes Reinecke 			    "Check Consistency Failed, status 0x%x\n", status);
2126081ff398SHannes Reinecke 
2127081ff398SHannes Reinecke 	return -EIO;
2128081ff398SHannes Reinecke }
2129081ff398SHannes Reinecke 
consistency_check_show(struct device * dev,struct device_attribute * attr,char * buf)2130081ff398SHannes Reinecke static ssize_t consistency_check_show(struct device *dev,
2131081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
2132081ff398SHannes Reinecke {
2133081ff398SHannes Reinecke 	return rebuild_show(dev, attr, buf);
2134081ff398SHannes Reinecke }
2135081ff398SHannes Reinecke static DEVICE_ATTR_RW(consistency_check);
2136081ff398SHannes Reinecke 
ctlr_num_show(struct device * dev,struct device_attribute * attr,char * buf)2137081ff398SHannes Reinecke static ssize_t ctlr_num_show(struct device *dev,
2138081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
2139081ff398SHannes Reinecke {
2140081ff398SHannes Reinecke 	struct Scsi_Host *shost = class_to_shost(dev);
2141081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
2142081ff398SHannes Reinecke 
2143fc29f04aSYe Bin 	return snprintf(buf, 20, "%u\n", cb->ctlr_num);
2144081ff398SHannes Reinecke }
2145081ff398SHannes Reinecke static DEVICE_ATTR_RO(ctlr_num);
2146081ff398SHannes Reinecke 
firmware_show(struct device * dev,struct device_attribute * attr,char * buf)2147081ff398SHannes Reinecke static ssize_t firmware_show(struct device *dev,
2148081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
2149081ff398SHannes Reinecke {
2150081ff398SHannes Reinecke 	struct Scsi_Host *shost = class_to_shost(dev);
2151081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
2152081ff398SHannes Reinecke 
2153081ff398SHannes Reinecke 	return snprintf(buf, 16, "%s\n", cb->fw_version);
2154081ff398SHannes Reinecke }
2155081ff398SHannes Reinecke static DEVICE_ATTR_RO(firmware);
2156081ff398SHannes Reinecke 
model_show(struct device * dev,struct device_attribute * attr,char * buf)2157081ff398SHannes Reinecke static ssize_t model_show(struct device *dev,
2158081ff398SHannes Reinecke 		struct device_attribute *attr, char *buf)
2159081ff398SHannes Reinecke {
2160081ff398SHannes Reinecke 	struct Scsi_Host *shost = class_to_shost(dev);
2161081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
2162081ff398SHannes Reinecke 
2163081ff398SHannes Reinecke 	return snprintf(buf, 16, "%s\n", cb->model_name);
2164081ff398SHannes Reinecke }
2165081ff398SHannes Reinecke static DEVICE_ATTR_RO(model);
2166081ff398SHannes Reinecke 
flush_cache_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2167081ff398SHannes Reinecke static ssize_t flush_cache_store(struct device *dev,
2168081ff398SHannes Reinecke 		struct device_attribute *attr, const char *buf, size_t count)
2169081ff398SHannes Reinecke {
2170081ff398SHannes Reinecke 	struct Scsi_Host *shost = class_to_shost(dev);
2171081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(shost);
2172081ff398SHannes Reinecke 	unsigned short status;
2173081ff398SHannes Reinecke 
2174081ff398SHannes Reinecke 	status = myrb_exec_type3(cb, MYRB_CMD_FLUSH, 0);
2175081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS) {
2176081ff398SHannes Reinecke 		shost_printk(KERN_INFO, shost,
2177081ff398SHannes Reinecke 			     "Cache Flush Completed\n");
2178081ff398SHannes Reinecke 		return count;
2179081ff398SHannes Reinecke 	}
2180081ff398SHannes Reinecke 	shost_printk(KERN_INFO, shost,
2181081ff398SHannes Reinecke 		     "Cache Flush Failed, status %x\n", status);
2182081ff398SHannes Reinecke 	return -EIO;
2183081ff398SHannes Reinecke }
2184081ff398SHannes Reinecke static DEVICE_ATTR_WO(flush_cache);
2185081ff398SHannes Reinecke 
2186582c0360SBart Van Assche static struct attribute *myrb_sdev_attrs[] = {
2187582c0360SBart Van Assche 	&dev_attr_rebuild.attr,
2188582c0360SBart Van Assche 	&dev_attr_consistency_check.attr,
2189582c0360SBart Van Assche 	&dev_attr_raid_state.attr,
2190582c0360SBart Van Assche 	&dev_attr_raid_level.attr,
2191081ff398SHannes Reinecke 	NULL,
2192081ff398SHannes Reinecke };
2193081ff398SHannes Reinecke 
2194582c0360SBart Van Assche ATTRIBUTE_GROUPS(myrb_sdev);
2195582c0360SBart Van Assche 
2196582c0360SBart Van Assche static struct attribute *myrb_shost_attrs[] = {
2197582c0360SBart Van Assche 	&dev_attr_ctlr_num.attr,
2198582c0360SBart Van Assche 	&dev_attr_model.attr,
2199582c0360SBart Van Assche 	&dev_attr_firmware.attr,
2200582c0360SBart Van Assche 	&dev_attr_flush_cache.attr,
2201081ff398SHannes Reinecke 	NULL,
2202081ff398SHannes Reinecke };
2203081ff398SHannes Reinecke 
2204582c0360SBart Van Assche ATTRIBUTE_GROUPS(myrb_shost);
2205582c0360SBart Van Assche 
22068e64d59dSBart Van Assche static const struct scsi_host_template myrb_template = {
2207081ff398SHannes Reinecke 	.module			= THIS_MODULE,
2208081ff398SHannes Reinecke 	.name			= "DAC960",
2209081ff398SHannes Reinecke 	.proc_name		= "myrb",
2210081ff398SHannes Reinecke 	.queuecommand		= myrb_queuecommand,
2211081ff398SHannes Reinecke 	.eh_host_reset_handler	= myrb_host_reset,
2212081ff398SHannes Reinecke 	.slave_alloc		= myrb_slave_alloc,
2213081ff398SHannes Reinecke 	.slave_configure	= myrb_slave_configure,
2214081ff398SHannes Reinecke 	.slave_destroy		= myrb_slave_destroy,
2215081ff398SHannes Reinecke 	.bios_param		= myrb_biosparam,
2216081ff398SHannes Reinecke 	.cmd_size		= sizeof(struct myrb_cmdblk),
2217582c0360SBart Van Assche 	.shost_groups		= myrb_shost_groups,
2218582c0360SBart Van Assche 	.sdev_groups		= myrb_sdev_groups,
2219081ff398SHannes Reinecke 	.this_id		= -1,
2220081ff398SHannes Reinecke };
2221081ff398SHannes Reinecke 
2222081ff398SHannes Reinecke /**
2223081ff398SHannes Reinecke  * myrb_is_raid - return boolean indicating device is raid volume
222412a1b740SLee Jones  * @dev: the device struct object
2225081ff398SHannes Reinecke  */
myrb_is_raid(struct device * dev)2226081ff398SHannes Reinecke static int myrb_is_raid(struct device *dev)
2227081ff398SHannes Reinecke {
2228081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
2229081ff398SHannes Reinecke 
2230081ff398SHannes Reinecke 	return sdev->channel == myrb_logical_channel(sdev->host);
2231081ff398SHannes Reinecke }
2232081ff398SHannes Reinecke 
2233081ff398SHannes Reinecke /**
2234081ff398SHannes Reinecke  * myrb_get_resync - get raid volume resync percent complete
223512a1b740SLee Jones  * @dev: the device struct object
2236081ff398SHannes Reinecke  */
myrb_get_resync(struct device * dev)2237081ff398SHannes Reinecke static void myrb_get_resync(struct device *dev)
2238081ff398SHannes Reinecke {
2239081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
2240081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
2241081ff398SHannes Reinecke 	struct myrb_rbld_progress rbld_buf;
2242081ff398SHannes Reinecke 	unsigned int percent_complete = 0;
2243081ff398SHannes Reinecke 	unsigned short status;
2244081ff398SHannes Reinecke 	unsigned int ldev_size = 0, remaining = 0;
2245081ff398SHannes Reinecke 
2246081ff398SHannes Reinecke 	if (sdev->channel < myrb_logical_channel(sdev->host))
2247081ff398SHannes Reinecke 		return;
2248081ff398SHannes Reinecke 	status = myrb_get_rbld_progress(cb, &rbld_buf);
2249081ff398SHannes Reinecke 	if (status == MYRB_STATUS_SUCCESS) {
2250081ff398SHannes Reinecke 		if (rbld_buf.ldev_num == sdev->id) {
2251081ff398SHannes Reinecke 			ldev_size = rbld_buf.ldev_size;
2252081ff398SHannes Reinecke 			remaining = rbld_buf.blocks_left;
2253081ff398SHannes Reinecke 		}
2254081ff398SHannes Reinecke 	}
2255081ff398SHannes Reinecke 	if (remaining && ldev_size)
2256081ff398SHannes Reinecke 		percent_complete = (ldev_size - remaining) * 100 / ldev_size;
2257081ff398SHannes Reinecke 	raid_set_resync(myrb_raid_template, dev, percent_complete);
2258081ff398SHannes Reinecke }
2259081ff398SHannes Reinecke 
2260081ff398SHannes Reinecke /**
2261081ff398SHannes Reinecke  * myrb_get_state - get raid volume status
226212a1b740SLee Jones  * @dev: the device struct object
2263081ff398SHannes Reinecke  */
myrb_get_state(struct device * dev)2264081ff398SHannes Reinecke static void myrb_get_state(struct device *dev)
2265081ff398SHannes Reinecke {
2266081ff398SHannes Reinecke 	struct scsi_device *sdev = to_scsi_device(dev);
2267081ff398SHannes Reinecke 	struct myrb_hba *cb = shost_priv(sdev->host);
2268081ff398SHannes Reinecke 	struct myrb_ldev_info *ldev_info = sdev->hostdata;
2269081ff398SHannes Reinecke 	enum raid_state state = RAID_STATE_UNKNOWN;
2270081ff398SHannes Reinecke 	unsigned short status;
2271081ff398SHannes Reinecke 
2272081ff398SHannes Reinecke 	if (sdev->channel < myrb_logical_channel(sdev->host) || !ldev_info)
2273081ff398SHannes Reinecke 		state = RAID_STATE_UNKNOWN;
2274081ff398SHannes Reinecke 	else {
2275081ff398SHannes Reinecke 		status = myrb_get_rbld_progress(cb, NULL);
2276081ff398SHannes Reinecke 		if (status == MYRB_STATUS_SUCCESS)
2277081ff398SHannes Reinecke 			state = RAID_STATE_RESYNCING;
2278081ff398SHannes Reinecke 		else {
2279081ff398SHannes Reinecke 			switch (ldev_info->state) {
2280081ff398SHannes Reinecke 			case MYRB_DEVICE_ONLINE:
2281081ff398SHannes Reinecke 				state = RAID_STATE_ACTIVE;
2282081ff398SHannes Reinecke 				break;
2283081ff398SHannes Reinecke 			case MYRB_DEVICE_WO:
2284081ff398SHannes Reinecke 			case MYRB_DEVICE_CRITICAL:
2285081ff398SHannes Reinecke 				state = RAID_STATE_DEGRADED;
2286081ff398SHannes Reinecke 				break;
2287081ff398SHannes Reinecke 			default:
2288081ff398SHannes Reinecke 				state = RAID_STATE_OFFLINE;
2289081ff398SHannes Reinecke 			}
2290081ff398SHannes Reinecke 		}
2291081ff398SHannes Reinecke 	}
2292081ff398SHannes Reinecke 	raid_set_state(myrb_raid_template, dev, state);
2293081ff398SHannes Reinecke }
2294081ff398SHannes Reinecke 
22959d8a5510SJason Yan static struct raid_function_template myrb_raid_functions = {
2296081ff398SHannes Reinecke 	.cookie		= &myrb_template,
2297081ff398SHannes Reinecke 	.is_raid	= myrb_is_raid,
2298081ff398SHannes Reinecke 	.get_resync	= myrb_get_resync,
2299081ff398SHannes Reinecke 	.get_state	= myrb_get_state,
2300081ff398SHannes Reinecke };
2301081ff398SHannes Reinecke 
myrb_handle_scsi(struct myrb_hba * cb,struct myrb_cmdblk * cmd_blk,struct scsi_cmnd * scmd)2302081ff398SHannes Reinecke static void myrb_handle_scsi(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk,
2303081ff398SHannes Reinecke 		struct scsi_cmnd *scmd)
2304081ff398SHannes Reinecke {
2305081ff398SHannes Reinecke 	unsigned short status;
2306081ff398SHannes Reinecke 
2307081ff398SHannes Reinecke 	if (!cmd_blk)
2308081ff398SHannes Reinecke 		return;
2309081ff398SHannes Reinecke 
2310081ff398SHannes Reinecke 	scsi_dma_unmap(scmd);
2311081ff398SHannes Reinecke 
2312081ff398SHannes Reinecke 	if (cmd_blk->dcdb) {
2313081ff398SHannes Reinecke 		memcpy(scmd->sense_buffer, &cmd_blk->dcdb->sense, 64);
2314081ff398SHannes Reinecke 		dma_pool_free(cb->dcdb_pool, cmd_blk->dcdb,
2315081ff398SHannes Reinecke 			      cmd_blk->dcdb_addr);
2316081ff398SHannes Reinecke 		cmd_blk->dcdb = NULL;
2317081ff398SHannes Reinecke 	}
2318081ff398SHannes Reinecke 	if (cmd_blk->sgl) {
2319081ff398SHannes Reinecke 		dma_pool_free(cb->sg_pool, cmd_blk->sgl, cmd_blk->sgl_addr);
2320081ff398SHannes Reinecke 		cmd_blk->sgl = NULL;
2321081ff398SHannes Reinecke 		cmd_blk->sgl_addr = 0;
2322081ff398SHannes Reinecke 	}
2323081ff398SHannes Reinecke 	status = cmd_blk->status;
2324081ff398SHannes Reinecke 	switch (status) {
2325081ff398SHannes Reinecke 	case MYRB_STATUS_SUCCESS:
2326081ff398SHannes Reinecke 	case MYRB_STATUS_DEVICE_BUSY:
2327081ff398SHannes Reinecke 		scmd->result = (DID_OK << 16) | status;
2328081ff398SHannes Reinecke 		break;
2329081ff398SHannes Reinecke 	case MYRB_STATUS_BAD_DATA:
2330081ff398SHannes Reinecke 		dev_dbg(&scmd->device->sdev_gendev,
2331081ff398SHannes Reinecke 			"Bad Data Encountered\n");
2332081ff398SHannes Reinecke 		if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2333081ff398SHannes Reinecke 			/* Unrecovered read error */
2334f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x11, 0);
2335081ff398SHannes Reinecke 		else
2336081ff398SHannes Reinecke 			/* Write error */
2337f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x0C, 0);
2338081ff398SHannes Reinecke 		break;
2339081ff398SHannes Reinecke 	case MYRB_STATUS_IRRECOVERABLE_DATA_ERROR:
2340081ff398SHannes Reinecke 		scmd_printk(KERN_ERR, scmd, "Irrecoverable Data Error\n");
2341081ff398SHannes Reinecke 		if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2342081ff398SHannes Reinecke 			/* Unrecovered read error, auto-reallocation failed */
2343f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x11, 0x04);
2344081ff398SHannes Reinecke 		else
2345081ff398SHannes Reinecke 			/* Write error, auto-reallocation failed */
2346f2b1e9c6SHannes Reinecke 			scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x0C, 0x02);
2347081ff398SHannes Reinecke 		break;
2348081ff398SHannes Reinecke 	case MYRB_STATUS_LDRV_NONEXISTENT_OR_OFFLINE:
2349081ff398SHannes Reinecke 		dev_dbg(&scmd->device->sdev_gendev,
2350081ff398SHannes Reinecke 			    "Logical Drive Nonexistent or Offline");
2351081ff398SHannes Reinecke 		scmd->result = (DID_BAD_TARGET << 16);
2352081ff398SHannes Reinecke 		break;
2353081ff398SHannes Reinecke 	case MYRB_STATUS_ACCESS_BEYOND_END_OF_LDRV:
2354081ff398SHannes Reinecke 		dev_dbg(&scmd->device->sdev_gendev,
2355081ff398SHannes Reinecke 			    "Attempt to Access Beyond End of Logical Drive");
2356081ff398SHannes Reinecke 		/* Logical block address out of range */
2357f2b1e9c6SHannes Reinecke 		scsi_build_sense(scmd, 0, NOT_READY, 0x21, 0);
2358081ff398SHannes Reinecke 		break;
2359081ff398SHannes Reinecke 	case MYRB_STATUS_DEVICE_NONRESPONSIVE:
2360081ff398SHannes Reinecke 		dev_dbg(&scmd->device->sdev_gendev, "Device nonresponsive\n");
2361081ff398SHannes Reinecke 		scmd->result = (DID_BAD_TARGET << 16);
2362081ff398SHannes Reinecke 		break;
2363081ff398SHannes Reinecke 	default:
2364081ff398SHannes Reinecke 		scmd_printk(KERN_ERR, scmd,
2365081ff398SHannes Reinecke 			    "Unexpected Error Status %04X", status);
2366081ff398SHannes Reinecke 		scmd->result = (DID_ERROR << 16);
2367081ff398SHannes Reinecke 		break;
2368081ff398SHannes Reinecke 	}
23690061e3f5SBart Van Assche 	scsi_done(scmd);
2370081ff398SHannes Reinecke }
2371081ff398SHannes Reinecke 
myrb_handle_cmdblk(struct myrb_hba * cb,struct myrb_cmdblk * cmd_blk)2372081ff398SHannes Reinecke static void myrb_handle_cmdblk(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
2373081ff398SHannes Reinecke {
2374081ff398SHannes Reinecke 	if (!cmd_blk)
2375081ff398SHannes Reinecke 		return;
2376081ff398SHannes Reinecke 
2377081ff398SHannes Reinecke 	if (cmd_blk->completion) {
2378081ff398SHannes Reinecke 		complete(cmd_blk->completion);
2379081ff398SHannes Reinecke 		cmd_blk->completion = NULL;
2380081ff398SHannes Reinecke 	}
2381081ff398SHannes Reinecke }
2382081ff398SHannes Reinecke 
myrb_monitor(struct work_struct * work)2383081ff398SHannes Reinecke static void myrb_monitor(struct work_struct *work)
2384081ff398SHannes Reinecke {
2385081ff398SHannes Reinecke 	struct myrb_hba *cb = container_of(work,
2386081ff398SHannes Reinecke 			struct myrb_hba, monitor_work.work);
2387081ff398SHannes Reinecke 	struct Scsi_Host *shost = cb->host;
2388081ff398SHannes Reinecke 	unsigned long interval = MYRB_PRIMARY_MONITOR_INTERVAL;
2389081ff398SHannes Reinecke 
2390081ff398SHannes Reinecke 	dev_dbg(&shost->shost_gendev, "monitor tick\n");
2391081ff398SHannes Reinecke 
2392081ff398SHannes Reinecke 	if (cb->new_ev_seq > cb->old_ev_seq) {
2393081ff398SHannes Reinecke 		int event = cb->old_ev_seq;
2394081ff398SHannes Reinecke 
2395081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev,
2396081ff398SHannes Reinecke 			"get event log no %d/%d\n",
2397081ff398SHannes Reinecke 			cb->new_ev_seq, event);
2398081ff398SHannes Reinecke 		myrb_get_event(cb, event);
2399081ff398SHannes Reinecke 		cb->old_ev_seq = event + 1;
2400081ff398SHannes Reinecke 		interval = 10;
2401081ff398SHannes Reinecke 	} else if (cb->need_err_info) {
2402081ff398SHannes Reinecke 		cb->need_err_info = false;
2403081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev, "get error table\n");
2404081ff398SHannes Reinecke 		myrb_get_errtable(cb);
2405081ff398SHannes Reinecke 		interval = 10;
2406081ff398SHannes Reinecke 	} else if (cb->need_rbld && cb->rbld_first) {
2407081ff398SHannes Reinecke 		cb->need_rbld = false;
2408081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev,
2409081ff398SHannes Reinecke 			"get rebuild progress\n");
2410081ff398SHannes Reinecke 		myrb_update_rbld_progress(cb);
2411081ff398SHannes Reinecke 		interval = 10;
2412081ff398SHannes Reinecke 	} else if (cb->need_ldev_info) {
2413081ff398SHannes Reinecke 		cb->need_ldev_info = false;
2414081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev,
2415081ff398SHannes Reinecke 			"get logical drive info\n");
2416081ff398SHannes Reinecke 		myrb_get_ldev_info(cb);
2417081ff398SHannes Reinecke 		interval = 10;
2418081ff398SHannes Reinecke 	} else if (cb->need_rbld) {
2419081ff398SHannes Reinecke 		cb->need_rbld = false;
2420081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev,
2421081ff398SHannes Reinecke 			"get rebuild progress\n");
2422081ff398SHannes Reinecke 		myrb_update_rbld_progress(cb);
2423081ff398SHannes Reinecke 		interval = 10;
2424081ff398SHannes Reinecke 	} else if (cb->need_cc_status) {
2425081ff398SHannes Reinecke 		cb->need_cc_status = false;
2426081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev,
2427081ff398SHannes Reinecke 			"get consistency check progress\n");
2428081ff398SHannes Reinecke 		myrb_get_cc_progress(cb);
2429081ff398SHannes Reinecke 		interval = 10;
2430081ff398SHannes Reinecke 	} else if (cb->need_bgi_status) {
2431081ff398SHannes Reinecke 		cb->need_bgi_status = false;
2432081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev, "get background init status\n");
2433081ff398SHannes Reinecke 		myrb_bgi_control(cb);
2434081ff398SHannes Reinecke 		interval = 10;
2435081ff398SHannes Reinecke 	} else {
2436081ff398SHannes Reinecke 		dev_dbg(&shost->shost_gendev, "new enquiry\n");
2437081ff398SHannes Reinecke 		mutex_lock(&cb->dma_mutex);
2438081ff398SHannes Reinecke 		myrb_hba_enquiry(cb);
2439081ff398SHannes Reinecke 		mutex_unlock(&cb->dma_mutex);
2440081ff398SHannes Reinecke 		if ((cb->new_ev_seq - cb->old_ev_seq > 0) ||
2441081ff398SHannes Reinecke 		    cb->need_err_info || cb->need_rbld ||
2442081ff398SHannes Reinecke 		    cb->need_ldev_info || cb->need_cc_status ||
2443081ff398SHannes Reinecke 		    cb->need_bgi_status) {
2444081ff398SHannes Reinecke 			dev_dbg(&shost->shost_gendev,
2445081ff398SHannes Reinecke 				"reschedule monitor\n");
2446081ff398SHannes Reinecke 			interval = 0;
2447081ff398SHannes Reinecke 		}
2448081ff398SHannes Reinecke 	}
2449081ff398SHannes Reinecke 	if (interval > 1)
2450081ff398SHannes Reinecke 		cb->primary_monitor_time = jiffies;
2451081ff398SHannes Reinecke 	queue_delayed_work(cb->work_q, &cb->monitor_work, interval);
2452081ff398SHannes Reinecke }
2453081ff398SHannes Reinecke 
245412a1b740SLee Jones /*
2455081ff398SHannes Reinecke  * myrb_err_status - reports controller BIOS messages
2456081ff398SHannes Reinecke  *
2457081ff398SHannes Reinecke  * Controller BIOS messages are passed through the Error Status Register
2458081ff398SHannes Reinecke  * when the driver performs the BIOS handshaking.
2459081ff398SHannes Reinecke  *
2460081ff398SHannes Reinecke  * Return: true for fatal errors and false otherwise.
2461081ff398SHannes Reinecke  */
myrb_err_status(struct myrb_hba * cb,unsigned char error,unsigned char parm0,unsigned char parm1)24629d8a5510SJason Yan static bool myrb_err_status(struct myrb_hba *cb, unsigned char error,
2463081ff398SHannes Reinecke 		unsigned char parm0, unsigned char parm1)
2464081ff398SHannes Reinecke {
2465081ff398SHannes Reinecke 	struct pci_dev *pdev = cb->pdev;
2466081ff398SHannes Reinecke 
2467081ff398SHannes Reinecke 	switch (error) {
2468081ff398SHannes Reinecke 	case 0x00:
2469081ff398SHannes Reinecke 		dev_info(&pdev->dev,
2470081ff398SHannes Reinecke 			 "Physical Device %d:%d Not Responding\n",
2471081ff398SHannes Reinecke 			 parm1, parm0);
2472081ff398SHannes Reinecke 		break;
2473081ff398SHannes Reinecke 	case 0x08:
2474081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Spinning Up Drives\n");
2475081ff398SHannes Reinecke 		break;
2476081ff398SHannes Reinecke 	case 0x30:
2477081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Configuration Checksum Error\n");
2478081ff398SHannes Reinecke 		break;
2479081ff398SHannes Reinecke 	case 0x60:
2480081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Mirror Race Recovery Failed\n");
2481081ff398SHannes Reinecke 		break;
2482081ff398SHannes Reinecke 	case 0x70:
2483081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Mirror Race Recovery In Progress\n");
2484081ff398SHannes Reinecke 		break;
2485081ff398SHannes Reinecke 	case 0x90:
2486081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Physical Device %d:%d COD Mismatch\n",
2487081ff398SHannes Reinecke 			   parm1, parm0);
2488081ff398SHannes Reinecke 		break;
2489081ff398SHannes Reinecke 	case 0xA0:
2490081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Logical Drive Installation Aborted\n");
2491081ff398SHannes Reinecke 		break;
2492081ff398SHannes Reinecke 	case 0xB0:
2493081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "Mirror Race On A Critical Logical Drive\n");
2494081ff398SHannes Reinecke 		break;
2495081ff398SHannes Reinecke 	case 0xD0:
2496081ff398SHannes Reinecke 		dev_notice(&pdev->dev, "New Controller Configuration Found\n");
2497081ff398SHannes Reinecke 		break;
2498081ff398SHannes Reinecke 	case 0xF0:
2499081ff398SHannes Reinecke 		dev_err(&pdev->dev, "Fatal Memory Parity Error\n");
2500081ff398SHannes Reinecke 		return true;
2501081ff398SHannes Reinecke 	default:
2502081ff398SHannes Reinecke 		dev_err(&pdev->dev, "Unknown Initialization Error %02X\n",
2503081ff398SHannes Reinecke 			error);
2504081ff398SHannes Reinecke 		return true;
2505081ff398SHannes Reinecke 	}
2506081ff398SHannes Reinecke 	return false;
2507081ff398SHannes Reinecke }
2508081ff398SHannes Reinecke 
2509081ff398SHannes Reinecke /*
2510081ff398SHannes Reinecke  * Hardware-specific functions
2511081ff398SHannes Reinecke  */
2512081ff398SHannes Reinecke 
2513081ff398SHannes Reinecke /*
2514081ff398SHannes Reinecke  * DAC960 LA Series Controllers
2515081ff398SHannes Reinecke  */
2516081ff398SHannes Reinecke 
DAC960_LA_hw_mbox_new_cmd(void __iomem * base)2517081ff398SHannes Reinecke static inline void DAC960_LA_hw_mbox_new_cmd(void __iomem *base)
2518081ff398SHannes Reinecke {
2519081ff398SHannes Reinecke 	writeb(DAC960_LA_IDB_HWMBOX_NEW_CMD, base + DAC960_LA_IDB_OFFSET);
2520081ff398SHannes Reinecke }
2521081ff398SHannes Reinecke 
DAC960_LA_ack_hw_mbox_status(void __iomem * base)2522081ff398SHannes Reinecke static inline void DAC960_LA_ack_hw_mbox_status(void __iomem *base)
2523081ff398SHannes Reinecke {
2524081ff398SHannes Reinecke 	writeb(DAC960_LA_IDB_HWMBOX_ACK_STS, base + DAC960_LA_IDB_OFFSET);
2525081ff398SHannes Reinecke }
2526081ff398SHannes Reinecke 
DAC960_LA_reset_ctrl(void __iomem * base)2527081ff398SHannes Reinecke static inline void DAC960_LA_reset_ctrl(void __iomem *base)
2528081ff398SHannes Reinecke {
2529081ff398SHannes Reinecke 	writeb(DAC960_LA_IDB_CTRL_RESET, base + DAC960_LA_IDB_OFFSET);
2530081ff398SHannes Reinecke }
2531081ff398SHannes Reinecke 
DAC960_LA_mem_mbox_new_cmd(void __iomem * base)2532081ff398SHannes Reinecke static inline void DAC960_LA_mem_mbox_new_cmd(void __iomem *base)
2533081ff398SHannes Reinecke {
2534081ff398SHannes Reinecke 	writeb(DAC960_LA_IDB_MMBOX_NEW_CMD, base + DAC960_LA_IDB_OFFSET);
2535081ff398SHannes Reinecke }
2536081ff398SHannes Reinecke 
DAC960_LA_hw_mbox_is_full(void __iomem * base)2537081ff398SHannes Reinecke static inline bool DAC960_LA_hw_mbox_is_full(void __iomem *base)
2538081ff398SHannes Reinecke {
2539081ff398SHannes Reinecke 	unsigned char idb = readb(base + DAC960_LA_IDB_OFFSET);
2540081ff398SHannes Reinecke 
2541081ff398SHannes Reinecke 	return !(idb & DAC960_LA_IDB_HWMBOX_EMPTY);
2542081ff398SHannes Reinecke }
2543081ff398SHannes Reinecke 
DAC960_LA_init_in_progress(void __iomem * base)2544081ff398SHannes Reinecke static inline bool DAC960_LA_init_in_progress(void __iomem *base)
2545081ff398SHannes Reinecke {
2546081ff398SHannes Reinecke 	unsigned char idb = readb(base + DAC960_LA_IDB_OFFSET);
2547081ff398SHannes Reinecke 
2548081ff398SHannes Reinecke 	return !(idb & DAC960_LA_IDB_INIT_DONE);
2549081ff398SHannes Reinecke }
2550081ff398SHannes Reinecke 
DAC960_LA_ack_hw_mbox_intr(void __iomem * base)2551081ff398SHannes Reinecke static inline void DAC960_LA_ack_hw_mbox_intr(void __iomem *base)
2552081ff398SHannes Reinecke {
2553081ff398SHannes Reinecke 	writeb(DAC960_LA_ODB_HWMBOX_ACK_IRQ, base + DAC960_LA_ODB_OFFSET);
2554081ff398SHannes Reinecke }
2555081ff398SHannes Reinecke 
DAC960_LA_ack_intr(void __iomem * base)2556081ff398SHannes Reinecke static inline void DAC960_LA_ack_intr(void __iomem *base)
2557081ff398SHannes Reinecke {
2558081ff398SHannes Reinecke 	writeb(DAC960_LA_ODB_HWMBOX_ACK_IRQ | DAC960_LA_ODB_MMBOX_ACK_IRQ,
2559081ff398SHannes Reinecke 	       base + DAC960_LA_ODB_OFFSET);
2560081ff398SHannes Reinecke }
2561081ff398SHannes Reinecke 
DAC960_LA_hw_mbox_status_available(void __iomem * base)2562081ff398SHannes Reinecke static inline bool DAC960_LA_hw_mbox_status_available(void __iomem *base)
2563081ff398SHannes Reinecke {
2564081ff398SHannes Reinecke 	unsigned char odb = readb(base + DAC960_LA_ODB_OFFSET);
2565081ff398SHannes Reinecke 
2566081ff398SHannes Reinecke 	return odb & DAC960_LA_ODB_HWMBOX_STS_AVAIL;
2567081ff398SHannes Reinecke }
2568081ff398SHannes Reinecke 
DAC960_LA_enable_intr(void __iomem * base)2569081ff398SHannes Reinecke static inline void DAC960_LA_enable_intr(void __iomem *base)
2570081ff398SHannes Reinecke {
2571081ff398SHannes Reinecke 	unsigned char odb = 0xFF;
2572081ff398SHannes Reinecke 
2573081ff398SHannes Reinecke 	odb &= ~DAC960_LA_IRQMASK_DISABLE_IRQ;
2574081ff398SHannes Reinecke 	writeb(odb, base + DAC960_LA_IRQMASK_OFFSET);
2575081ff398SHannes Reinecke }
2576081ff398SHannes Reinecke 
DAC960_LA_disable_intr(void __iomem * base)2577081ff398SHannes Reinecke static inline void DAC960_LA_disable_intr(void __iomem *base)
2578081ff398SHannes Reinecke {
2579081ff398SHannes Reinecke 	unsigned char odb = 0xFF;
2580081ff398SHannes Reinecke 
2581081ff398SHannes Reinecke 	odb |= DAC960_LA_IRQMASK_DISABLE_IRQ;
2582081ff398SHannes Reinecke 	writeb(odb, base + DAC960_LA_IRQMASK_OFFSET);
2583081ff398SHannes Reinecke }
2584081ff398SHannes Reinecke 
DAC960_LA_write_cmd_mbox(union myrb_cmd_mbox * mem_mbox,union myrb_cmd_mbox * mbox)2585081ff398SHannes Reinecke static inline void DAC960_LA_write_cmd_mbox(union myrb_cmd_mbox *mem_mbox,
2586081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
2587081ff398SHannes Reinecke {
2588081ff398SHannes Reinecke 	mem_mbox->words[1] = mbox->words[1];
2589081ff398SHannes Reinecke 	mem_mbox->words[2] = mbox->words[2];
2590081ff398SHannes Reinecke 	mem_mbox->words[3] = mbox->words[3];
2591081ff398SHannes Reinecke 	/* Memory barrier to prevent reordering */
2592081ff398SHannes Reinecke 	wmb();
2593081ff398SHannes Reinecke 	mem_mbox->words[0] = mbox->words[0];
2594081ff398SHannes Reinecke 	/* Memory barrier to force PCI access */
2595081ff398SHannes Reinecke 	mb();
2596081ff398SHannes Reinecke }
2597081ff398SHannes Reinecke 
DAC960_LA_write_hw_mbox(void __iomem * base,union myrb_cmd_mbox * mbox)2598081ff398SHannes Reinecke static inline void DAC960_LA_write_hw_mbox(void __iomem *base,
2599081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
2600081ff398SHannes Reinecke {
2601081ff398SHannes Reinecke 	writel(mbox->words[0], base + DAC960_LA_CMDOP_OFFSET);
2602081ff398SHannes Reinecke 	writel(mbox->words[1], base + DAC960_LA_MBOX4_OFFSET);
2603081ff398SHannes Reinecke 	writel(mbox->words[2], base + DAC960_LA_MBOX8_OFFSET);
2604081ff398SHannes Reinecke 	writeb(mbox->bytes[12], base + DAC960_LA_MBOX12_OFFSET);
2605081ff398SHannes Reinecke }
2606081ff398SHannes Reinecke 
DAC960_LA_read_status(void __iomem * base)2607081ff398SHannes Reinecke static inline unsigned short DAC960_LA_read_status(void __iomem *base)
2608081ff398SHannes Reinecke {
2609081ff398SHannes Reinecke 	return readw(base + DAC960_LA_STS_OFFSET);
2610081ff398SHannes Reinecke }
2611081ff398SHannes Reinecke 
2612081ff398SHannes Reinecke static inline bool
DAC960_LA_read_error_status(void __iomem * base,unsigned char * error,unsigned char * param0,unsigned char * param1)2613081ff398SHannes Reinecke DAC960_LA_read_error_status(void __iomem *base, unsigned char *error,
2614081ff398SHannes Reinecke 		unsigned char *param0, unsigned char *param1)
2615081ff398SHannes Reinecke {
2616081ff398SHannes Reinecke 	unsigned char errsts = readb(base + DAC960_LA_ERRSTS_OFFSET);
2617081ff398SHannes Reinecke 
2618081ff398SHannes Reinecke 	if (!(errsts & DAC960_LA_ERRSTS_PENDING))
2619081ff398SHannes Reinecke 		return false;
2620081ff398SHannes Reinecke 	errsts &= ~DAC960_LA_ERRSTS_PENDING;
2621081ff398SHannes Reinecke 
2622081ff398SHannes Reinecke 	*error = errsts;
2623081ff398SHannes Reinecke 	*param0 = readb(base + DAC960_LA_CMDOP_OFFSET);
2624081ff398SHannes Reinecke 	*param1 = readb(base + DAC960_LA_CMDID_OFFSET);
2625081ff398SHannes Reinecke 	writeb(0xFF, base + DAC960_LA_ERRSTS_OFFSET);
2626081ff398SHannes Reinecke 	return true;
2627081ff398SHannes Reinecke }
2628081ff398SHannes Reinecke 
2629081ff398SHannes Reinecke static inline unsigned short
DAC960_LA_mbox_init(struct pci_dev * pdev,void __iomem * base,union myrb_cmd_mbox * mbox)2630081ff398SHannes Reinecke DAC960_LA_mbox_init(struct pci_dev *pdev, void __iomem *base,
2631081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
2632081ff398SHannes Reinecke {
2633081ff398SHannes Reinecke 	unsigned short status;
2634081ff398SHannes Reinecke 	int timeout = 0;
2635081ff398SHannes Reinecke 
2636081ff398SHannes Reinecke 	while (timeout < MYRB_MAILBOX_TIMEOUT) {
2637081ff398SHannes Reinecke 		if (!DAC960_LA_hw_mbox_is_full(base))
2638081ff398SHannes Reinecke 			break;
2639081ff398SHannes Reinecke 		udelay(10);
2640081ff398SHannes Reinecke 		timeout++;
2641081ff398SHannes Reinecke 	}
2642081ff398SHannes Reinecke 	if (DAC960_LA_hw_mbox_is_full(base)) {
2643081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2644081ff398SHannes Reinecke 			"Timeout waiting for empty mailbox\n");
2645081ff398SHannes Reinecke 		return MYRB_STATUS_SUBSYS_TIMEOUT;
2646081ff398SHannes Reinecke 	}
2647081ff398SHannes Reinecke 	DAC960_LA_write_hw_mbox(base, mbox);
2648081ff398SHannes Reinecke 	DAC960_LA_hw_mbox_new_cmd(base);
2649081ff398SHannes Reinecke 	timeout = 0;
2650081ff398SHannes Reinecke 	while (timeout < MYRB_MAILBOX_TIMEOUT) {
2651081ff398SHannes Reinecke 		if (DAC960_LA_hw_mbox_status_available(base))
2652081ff398SHannes Reinecke 			break;
2653081ff398SHannes Reinecke 		udelay(10);
2654081ff398SHannes Reinecke 		timeout++;
2655081ff398SHannes Reinecke 	}
2656081ff398SHannes Reinecke 	if (!DAC960_LA_hw_mbox_status_available(base)) {
2657081ff398SHannes Reinecke 		dev_err(&pdev->dev, "Timeout waiting for mailbox status\n");
2658081ff398SHannes Reinecke 		return MYRB_STATUS_SUBSYS_TIMEOUT;
2659081ff398SHannes Reinecke 	}
2660081ff398SHannes Reinecke 	status = DAC960_LA_read_status(base);
2661081ff398SHannes Reinecke 	DAC960_LA_ack_hw_mbox_intr(base);
2662081ff398SHannes Reinecke 	DAC960_LA_ack_hw_mbox_status(base);
2663081ff398SHannes Reinecke 
2664081ff398SHannes Reinecke 	return status;
2665081ff398SHannes Reinecke }
2666081ff398SHannes Reinecke 
DAC960_LA_hw_init(struct pci_dev * pdev,struct myrb_hba * cb,void __iomem * base)2667081ff398SHannes Reinecke static int DAC960_LA_hw_init(struct pci_dev *pdev,
2668081ff398SHannes Reinecke 		struct myrb_hba *cb, void __iomem *base)
2669081ff398SHannes Reinecke {
2670081ff398SHannes Reinecke 	int timeout = 0;
2671081ff398SHannes Reinecke 	unsigned char error, parm0, parm1;
2672081ff398SHannes Reinecke 
2673081ff398SHannes Reinecke 	DAC960_LA_disable_intr(base);
2674081ff398SHannes Reinecke 	DAC960_LA_ack_hw_mbox_status(base);
2675081ff398SHannes Reinecke 	udelay(1000);
2676081ff398SHannes Reinecke 	while (DAC960_LA_init_in_progress(base) &&
2677081ff398SHannes Reinecke 	       timeout < MYRB_MAILBOX_TIMEOUT) {
2678081ff398SHannes Reinecke 		if (DAC960_LA_read_error_status(base, &error,
2679081ff398SHannes Reinecke 					      &parm0, &parm1) &&
2680081ff398SHannes Reinecke 		    myrb_err_status(cb, error, parm0, parm1))
2681081ff398SHannes Reinecke 			return -ENODEV;
2682081ff398SHannes Reinecke 		udelay(10);
2683081ff398SHannes Reinecke 		timeout++;
2684081ff398SHannes Reinecke 	}
2685081ff398SHannes Reinecke 	if (timeout == MYRB_MAILBOX_TIMEOUT) {
2686081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2687081ff398SHannes Reinecke 			"Timeout waiting for Controller Initialisation\n");
2688081ff398SHannes Reinecke 		return -ETIMEDOUT;
2689081ff398SHannes Reinecke 	}
2690081ff398SHannes Reinecke 	if (!myrb_enable_mmio(cb, DAC960_LA_mbox_init)) {
2691081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2692081ff398SHannes Reinecke 			"Unable to Enable Memory Mailbox Interface\n");
2693081ff398SHannes Reinecke 		DAC960_LA_reset_ctrl(base);
2694081ff398SHannes Reinecke 		return -ENODEV;
2695081ff398SHannes Reinecke 	}
2696081ff398SHannes Reinecke 	DAC960_LA_enable_intr(base);
2697081ff398SHannes Reinecke 	cb->qcmd = myrb_qcmd;
2698081ff398SHannes Reinecke 	cb->write_cmd_mbox = DAC960_LA_write_cmd_mbox;
2699081ff398SHannes Reinecke 	if (cb->dual_mode_interface)
2700081ff398SHannes Reinecke 		cb->get_cmd_mbox = DAC960_LA_mem_mbox_new_cmd;
2701081ff398SHannes Reinecke 	else
2702081ff398SHannes Reinecke 		cb->get_cmd_mbox = DAC960_LA_hw_mbox_new_cmd;
2703081ff398SHannes Reinecke 	cb->disable_intr = DAC960_LA_disable_intr;
2704081ff398SHannes Reinecke 	cb->reset = DAC960_LA_reset_ctrl;
2705081ff398SHannes Reinecke 
2706081ff398SHannes Reinecke 	return 0;
2707081ff398SHannes Reinecke }
2708081ff398SHannes Reinecke 
DAC960_LA_intr_handler(int irq,void * arg)2709081ff398SHannes Reinecke static irqreturn_t DAC960_LA_intr_handler(int irq, void *arg)
2710081ff398SHannes Reinecke {
2711081ff398SHannes Reinecke 	struct myrb_hba *cb = arg;
2712081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
2713081ff398SHannes Reinecke 	struct myrb_stat_mbox *next_stat_mbox;
2714081ff398SHannes Reinecke 	unsigned long flags;
2715081ff398SHannes Reinecke 
2716081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
2717081ff398SHannes Reinecke 	DAC960_LA_ack_intr(base);
2718081ff398SHannes Reinecke 	next_stat_mbox = cb->next_stat_mbox;
2719081ff398SHannes Reinecke 	while (next_stat_mbox->valid) {
2720081ff398SHannes Reinecke 		unsigned char id = next_stat_mbox->id;
2721081ff398SHannes Reinecke 		struct scsi_cmnd *scmd = NULL;
2722081ff398SHannes Reinecke 		struct myrb_cmdblk *cmd_blk = NULL;
2723081ff398SHannes Reinecke 
2724081ff398SHannes Reinecke 		if (id == MYRB_DCMD_TAG)
2725081ff398SHannes Reinecke 			cmd_blk = &cb->dcmd_blk;
2726081ff398SHannes Reinecke 		else if (id == MYRB_MCMD_TAG)
2727081ff398SHannes Reinecke 			cmd_blk = &cb->mcmd_blk;
2728081ff398SHannes Reinecke 		else {
2729081ff398SHannes Reinecke 			scmd = scsi_host_find_tag(cb->host, id - 3);
2730081ff398SHannes Reinecke 			if (scmd)
2731081ff398SHannes Reinecke 				cmd_blk = scsi_cmd_priv(scmd);
2732081ff398SHannes Reinecke 		}
2733081ff398SHannes Reinecke 		if (cmd_blk)
2734081ff398SHannes Reinecke 			cmd_blk->status = next_stat_mbox->status;
2735081ff398SHannes Reinecke 		else
2736081ff398SHannes Reinecke 			dev_err(&cb->pdev->dev,
2737081ff398SHannes Reinecke 				"Unhandled command completion %d\n", id);
2738081ff398SHannes Reinecke 
2739081ff398SHannes Reinecke 		memset(next_stat_mbox, 0, sizeof(struct myrb_stat_mbox));
2740081ff398SHannes Reinecke 		if (++next_stat_mbox > cb->last_stat_mbox)
2741081ff398SHannes Reinecke 			next_stat_mbox = cb->first_stat_mbox;
2742081ff398SHannes Reinecke 
2743081ff398SHannes Reinecke 		if (cmd_blk) {
2744081ff398SHannes Reinecke 			if (id < 3)
2745081ff398SHannes Reinecke 				myrb_handle_cmdblk(cb, cmd_blk);
2746081ff398SHannes Reinecke 			else
2747081ff398SHannes Reinecke 				myrb_handle_scsi(cb, cmd_blk, scmd);
2748081ff398SHannes Reinecke 		}
2749081ff398SHannes Reinecke 	}
2750081ff398SHannes Reinecke 	cb->next_stat_mbox = next_stat_mbox;
2751081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
2752081ff398SHannes Reinecke 	return IRQ_HANDLED;
2753081ff398SHannes Reinecke }
2754081ff398SHannes Reinecke 
2755182ad87cSShixin Liu static struct myrb_privdata DAC960_LA_privdata = {
2756081ff398SHannes Reinecke 	.hw_init =	DAC960_LA_hw_init,
2757081ff398SHannes Reinecke 	.irq_handler =	DAC960_LA_intr_handler,
2758081ff398SHannes Reinecke 	.mmio_size =	DAC960_LA_mmio_size,
2759081ff398SHannes Reinecke };
2760081ff398SHannes Reinecke 
2761081ff398SHannes Reinecke /*
2762081ff398SHannes Reinecke  * DAC960 PG Series Controllers
2763081ff398SHannes Reinecke  */
DAC960_PG_hw_mbox_new_cmd(void __iomem * base)2764081ff398SHannes Reinecke static inline void DAC960_PG_hw_mbox_new_cmd(void __iomem *base)
2765081ff398SHannes Reinecke {
2766081ff398SHannes Reinecke 	writel(DAC960_PG_IDB_HWMBOX_NEW_CMD, base + DAC960_PG_IDB_OFFSET);
2767081ff398SHannes Reinecke }
2768081ff398SHannes Reinecke 
DAC960_PG_ack_hw_mbox_status(void __iomem * base)2769081ff398SHannes Reinecke static inline void DAC960_PG_ack_hw_mbox_status(void __iomem *base)
2770081ff398SHannes Reinecke {
2771081ff398SHannes Reinecke 	writel(DAC960_PG_IDB_HWMBOX_ACK_STS, base + DAC960_PG_IDB_OFFSET);
2772081ff398SHannes Reinecke }
2773081ff398SHannes Reinecke 
DAC960_PG_reset_ctrl(void __iomem * base)2774081ff398SHannes Reinecke static inline void DAC960_PG_reset_ctrl(void __iomem *base)
2775081ff398SHannes Reinecke {
2776081ff398SHannes Reinecke 	writel(DAC960_PG_IDB_CTRL_RESET, base + DAC960_PG_IDB_OFFSET);
2777081ff398SHannes Reinecke }
2778081ff398SHannes Reinecke 
DAC960_PG_mem_mbox_new_cmd(void __iomem * base)2779081ff398SHannes Reinecke static inline void DAC960_PG_mem_mbox_new_cmd(void __iomem *base)
2780081ff398SHannes Reinecke {
2781081ff398SHannes Reinecke 	writel(DAC960_PG_IDB_MMBOX_NEW_CMD, base + DAC960_PG_IDB_OFFSET);
2782081ff398SHannes Reinecke }
2783081ff398SHannes Reinecke 
DAC960_PG_hw_mbox_is_full(void __iomem * base)2784081ff398SHannes Reinecke static inline bool DAC960_PG_hw_mbox_is_full(void __iomem *base)
2785081ff398SHannes Reinecke {
2786081ff398SHannes Reinecke 	unsigned char idb = readl(base + DAC960_PG_IDB_OFFSET);
2787081ff398SHannes Reinecke 
2788081ff398SHannes Reinecke 	return idb & DAC960_PG_IDB_HWMBOX_FULL;
2789081ff398SHannes Reinecke }
2790081ff398SHannes Reinecke 
DAC960_PG_init_in_progress(void __iomem * base)2791081ff398SHannes Reinecke static inline bool DAC960_PG_init_in_progress(void __iomem *base)
2792081ff398SHannes Reinecke {
2793081ff398SHannes Reinecke 	unsigned char idb = readl(base + DAC960_PG_IDB_OFFSET);
2794081ff398SHannes Reinecke 
2795081ff398SHannes Reinecke 	return idb & DAC960_PG_IDB_INIT_IN_PROGRESS;
2796081ff398SHannes Reinecke }
2797081ff398SHannes Reinecke 
DAC960_PG_ack_hw_mbox_intr(void __iomem * base)2798081ff398SHannes Reinecke static inline void DAC960_PG_ack_hw_mbox_intr(void __iomem *base)
2799081ff398SHannes Reinecke {
2800081ff398SHannes Reinecke 	writel(DAC960_PG_ODB_HWMBOX_ACK_IRQ, base + DAC960_PG_ODB_OFFSET);
2801081ff398SHannes Reinecke }
2802081ff398SHannes Reinecke 
DAC960_PG_ack_intr(void __iomem * base)2803081ff398SHannes Reinecke static inline void DAC960_PG_ack_intr(void __iomem *base)
2804081ff398SHannes Reinecke {
2805081ff398SHannes Reinecke 	writel(DAC960_PG_ODB_HWMBOX_ACK_IRQ | DAC960_PG_ODB_MMBOX_ACK_IRQ,
2806081ff398SHannes Reinecke 	       base + DAC960_PG_ODB_OFFSET);
2807081ff398SHannes Reinecke }
2808081ff398SHannes Reinecke 
DAC960_PG_hw_mbox_status_available(void __iomem * base)2809081ff398SHannes Reinecke static inline bool DAC960_PG_hw_mbox_status_available(void __iomem *base)
2810081ff398SHannes Reinecke {
2811081ff398SHannes Reinecke 	unsigned char odb = readl(base + DAC960_PG_ODB_OFFSET);
2812081ff398SHannes Reinecke 
2813081ff398SHannes Reinecke 	return odb & DAC960_PG_ODB_HWMBOX_STS_AVAIL;
2814081ff398SHannes Reinecke }
2815081ff398SHannes Reinecke 
DAC960_PG_enable_intr(void __iomem * base)2816081ff398SHannes Reinecke static inline void DAC960_PG_enable_intr(void __iomem *base)
2817081ff398SHannes Reinecke {
2818081ff398SHannes Reinecke 	unsigned int imask = (unsigned int)-1;
2819081ff398SHannes Reinecke 
2820081ff398SHannes Reinecke 	imask &= ~DAC960_PG_IRQMASK_DISABLE_IRQ;
2821081ff398SHannes Reinecke 	writel(imask, base + DAC960_PG_IRQMASK_OFFSET);
2822081ff398SHannes Reinecke }
2823081ff398SHannes Reinecke 
DAC960_PG_disable_intr(void __iomem * base)2824081ff398SHannes Reinecke static inline void DAC960_PG_disable_intr(void __iomem *base)
2825081ff398SHannes Reinecke {
2826081ff398SHannes Reinecke 	unsigned int imask = (unsigned int)-1;
2827081ff398SHannes Reinecke 
2828081ff398SHannes Reinecke 	writel(imask, base + DAC960_PG_IRQMASK_OFFSET);
2829081ff398SHannes Reinecke }
2830081ff398SHannes Reinecke 
DAC960_PG_write_cmd_mbox(union myrb_cmd_mbox * mem_mbox,union myrb_cmd_mbox * mbox)2831081ff398SHannes Reinecke static inline void DAC960_PG_write_cmd_mbox(union myrb_cmd_mbox *mem_mbox,
2832081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
2833081ff398SHannes Reinecke {
2834081ff398SHannes Reinecke 	mem_mbox->words[1] = mbox->words[1];
2835081ff398SHannes Reinecke 	mem_mbox->words[2] = mbox->words[2];
2836081ff398SHannes Reinecke 	mem_mbox->words[3] = mbox->words[3];
2837081ff398SHannes Reinecke 	/* Memory barrier to prevent reordering */
2838081ff398SHannes Reinecke 	wmb();
2839081ff398SHannes Reinecke 	mem_mbox->words[0] = mbox->words[0];
2840081ff398SHannes Reinecke 	/* Memory barrier to force PCI access */
2841081ff398SHannes Reinecke 	mb();
2842081ff398SHannes Reinecke }
2843081ff398SHannes Reinecke 
DAC960_PG_write_hw_mbox(void __iomem * base,union myrb_cmd_mbox * mbox)2844081ff398SHannes Reinecke static inline void DAC960_PG_write_hw_mbox(void __iomem *base,
2845081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
2846081ff398SHannes Reinecke {
2847081ff398SHannes Reinecke 	writel(mbox->words[0], base + DAC960_PG_CMDOP_OFFSET);
2848081ff398SHannes Reinecke 	writel(mbox->words[1], base + DAC960_PG_MBOX4_OFFSET);
2849081ff398SHannes Reinecke 	writel(mbox->words[2], base + DAC960_PG_MBOX8_OFFSET);
2850081ff398SHannes Reinecke 	writeb(mbox->bytes[12], base + DAC960_PG_MBOX12_OFFSET);
2851081ff398SHannes Reinecke }
2852081ff398SHannes Reinecke 
2853081ff398SHannes Reinecke static inline unsigned short
DAC960_PG_read_status(void __iomem * base)2854081ff398SHannes Reinecke DAC960_PG_read_status(void __iomem *base)
2855081ff398SHannes Reinecke {
2856081ff398SHannes Reinecke 	return readw(base + DAC960_PG_STS_OFFSET);
2857081ff398SHannes Reinecke }
2858081ff398SHannes Reinecke 
2859081ff398SHannes Reinecke static inline bool
DAC960_PG_read_error_status(void __iomem * base,unsigned char * error,unsigned char * param0,unsigned char * param1)2860081ff398SHannes Reinecke DAC960_PG_read_error_status(void __iomem *base, unsigned char *error,
2861081ff398SHannes Reinecke 		unsigned char *param0, unsigned char *param1)
2862081ff398SHannes Reinecke {
2863081ff398SHannes Reinecke 	unsigned char errsts = readb(base + DAC960_PG_ERRSTS_OFFSET);
2864081ff398SHannes Reinecke 
2865081ff398SHannes Reinecke 	if (!(errsts & DAC960_PG_ERRSTS_PENDING))
2866081ff398SHannes Reinecke 		return false;
2867081ff398SHannes Reinecke 	errsts &= ~DAC960_PG_ERRSTS_PENDING;
2868081ff398SHannes Reinecke 	*error = errsts;
2869081ff398SHannes Reinecke 	*param0 = readb(base + DAC960_PG_CMDOP_OFFSET);
2870081ff398SHannes Reinecke 	*param1 = readb(base + DAC960_PG_CMDID_OFFSET);
2871081ff398SHannes Reinecke 	writeb(0, base + DAC960_PG_ERRSTS_OFFSET);
2872081ff398SHannes Reinecke 	return true;
2873081ff398SHannes Reinecke }
2874081ff398SHannes Reinecke 
2875081ff398SHannes Reinecke static inline unsigned short
DAC960_PG_mbox_init(struct pci_dev * pdev,void __iomem * base,union myrb_cmd_mbox * mbox)2876081ff398SHannes Reinecke DAC960_PG_mbox_init(struct pci_dev *pdev, void __iomem *base,
2877081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
2878081ff398SHannes Reinecke {
2879081ff398SHannes Reinecke 	unsigned short status;
2880081ff398SHannes Reinecke 	int timeout = 0;
2881081ff398SHannes Reinecke 
2882081ff398SHannes Reinecke 	while (timeout < MYRB_MAILBOX_TIMEOUT) {
2883081ff398SHannes Reinecke 		if (!DAC960_PG_hw_mbox_is_full(base))
2884081ff398SHannes Reinecke 			break;
2885081ff398SHannes Reinecke 		udelay(10);
2886081ff398SHannes Reinecke 		timeout++;
2887081ff398SHannes Reinecke 	}
2888081ff398SHannes Reinecke 	if (DAC960_PG_hw_mbox_is_full(base)) {
2889081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2890081ff398SHannes Reinecke 			"Timeout waiting for empty mailbox\n");
2891081ff398SHannes Reinecke 		return MYRB_STATUS_SUBSYS_TIMEOUT;
2892081ff398SHannes Reinecke 	}
2893081ff398SHannes Reinecke 	DAC960_PG_write_hw_mbox(base, mbox);
2894081ff398SHannes Reinecke 	DAC960_PG_hw_mbox_new_cmd(base);
2895081ff398SHannes Reinecke 
2896081ff398SHannes Reinecke 	timeout = 0;
2897081ff398SHannes Reinecke 	while (timeout < MYRB_MAILBOX_TIMEOUT) {
2898081ff398SHannes Reinecke 		if (DAC960_PG_hw_mbox_status_available(base))
2899081ff398SHannes Reinecke 			break;
2900081ff398SHannes Reinecke 		udelay(10);
2901081ff398SHannes Reinecke 		timeout++;
2902081ff398SHannes Reinecke 	}
2903081ff398SHannes Reinecke 	if (!DAC960_PG_hw_mbox_status_available(base)) {
2904081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2905081ff398SHannes Reinecke 			"Timeout waiting for mailbox status\n");
2906081ff398SHannes Reinecke 		return MYRB_STATUS_SUBSYS_TIMEOUT;
2907081ff398SHannes Reinecke 	}
2908081ff398SHannes Reinecke 	status = DAC960_PG_read_status(base);
2909081ff398SHannes Reinecke 	DAC960_PG_ack_hw_mbox_intr(base);
2910081ff398SHannes Reinecke 	DAC960_PG_ack_hw_mbox_status(base);
2911081ff398SHannes Reinecke 
2912081ff398SHannes Reinecke 	return status;
2913081ff398SHannes Reinecke }
2914081ff398SHannes Reinecke 
DAC960_PG_hw_init(struct pci_dev * pdev,struct myrb_hba * cb,void __iomem * base)2915081ff398SHannes Reinecke static int DAC960_PG_hw_init(struct pci_dev *pdev,
2916081ff398SHannes Reinecke 		struct myrb_hba *cb, void __iomem *base)
2917081ff398SHannes Reinecke {
2918081ff398SHannes Reinecke 	int timeout = 0;
2919081ff398SHannes Reinecke 	unsigned char error, parm0, parm1;
2920081ff398SHannes Reinecke 
2921081ff398SHannes Reinecke 	DAC960_PG_disable_intr(base);
2922081ff398SHannes Reinecke 	DAC960_PG_ack_hw_mbox_status(base);
2923081ff398SHannes Reinecke 	udelay(1000);
2924081ff398SHannes Reinecke 	while (DAC960_PG_init_in_progress(base) &&
2925081ff398SHannes Reinecke 	       timeout < MYRB_MAILBOX_TIMEOUT) {
2926081ff398SHannes Reinecke 		if (DAC960_PG_read_error_status(base, &error,
2927081ff398SHannes Reinecke 						&parm0, &parm1) &&
2928081ff398SHannes Reinecke 		    myrb_err_status(cb, error, parm0, parm1))
2929081ff398SHannes Reinecke 			return -EIO;
2930081ff398SHannes Reinecke 		udelay(10);
2931081ff398SHannes Reinecke 		timeout++;
2932081ff398SHannes Reinecke 	}
2933081ff398SHannes Reinecke 	if (timeout == MYRB_MAILBOX_TIMEOUT) {
2934081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2935081ff398SHannes Reinecke 			"Timeout waiting for Controller Initialisation\n");
2936081ff398SHannes Reinecke 		return -ETIMEDOUT;
2937081ff398SHannes Reinecke 	}
2938081ff398SHannes Reinecke 	if (!myrb_enable_mmio(cb, DAC960_PG_mbox_init)) {
2939081ff398SHannes Reinecke 		dev_err(&pdev->dev,
2940081ff398SHannes Reinecke 			"Unable to Enable Memory Mailbox Interface\n");
2941081ff398SHannes Reinecke 		DAC960_PG_reset_ctrl(base);
2942081ff398SHannes Reinecke 		return -ENODEV;
2943081ff398SHannes Reinecke 	}
2944081ff398SHannes Reinecke 	DAC960_PG_enable_intr(base);
2945081ff398SHannes Reinecke 	cb->qcmd = myrb_qcmd;
2946081ff398SHannes Reinecke 	cb->write_cmd_mbox = DAC960_PG_write_cmd_mbox;
2947081ff398SHannes Reinecke 	if (cb->dual_mode_interface)
2948081ff398SHannes Reinecke 		cb->get_cmd_mbox = DAC960_PG_mem_mbox_new_cmd;
2949081ff398SHannes Reinecke 	else
2950081ff398SHannes Reinecke 		cb->get_cmd_mbox = DAC960_PG_hw_mbox_new_cmd;
2951081ff398SHannes Reinecke 	cb->disable_intr = DAC960_PG_disable_intr;
2952081ff398SHannes Reinecke 	cb->reset = DAC960_PG_reset_ctrl;
2953081ff398SHannes Reinecke 
2954081ff398SHannes Reinecke 	return 0;
2955081ff398SHannes Reinecke }
2956081ff398SHannes Reinecke 
DAC960_PG_intr_handler(int irq,void * arg)2957081ff398SHannes Reinecke static irqreturn_t DAC960_PG_intr_handler(int irq, void *arg)
2958081ff398SHannes Reinecke {
2959081ff398SHannes Reinecke 	struct myrb_hba *cb = arg;
2960081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
2961081ff398SHannes Reinecke 	struct myrb_stat_mbox *next_stat_mbox;
2962081ff398SHannes Reinecke 	unsigned long flags;
2963081ff398SHannes Reinecke 
2964081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
2965081ff398SHannes Reinecke 	DAC960_PG_ack_intr(base);
2966081ff398SHannes Reinecke 	next_stat_mbox = cb->next_stat_mbox;
2967081ff398SHannes Reinecke 	while (next_stat_mbox->valid) {
2968081ff398SHannes Reinecke 		unsigned char id = next_stat_mbox->id;
2969081ff398SHannes Reinecke 		struct scsi_cmnd *scmd = NULL;
2970081ff398SHannes Reinecke 		struct myrb_cmdblk *cmd_blk = NULL;
2971081ff398SHannes Reinecke 
2972081ff398SHannes Reinecke 		if (id == MYRB_DCMD_TAG)
2973081ff398SHannes Reinecke 			cmd_blk = &cb->dcmd_blk;
2974081ff398SHannes Reinecke 		else if (id == MYRB_MCMD_TAG)
2975081ff398SHannes Reinecke 			cmd_blk = &cb->mcmd_blk;
2976081ff398SHannes Reinecke 		else {
2977081ff398SHannes Reinecke 			scmd = scsi_host_find_tag(cb->host, id - 3);
2978081ff398SHannes Reinecke 			if (scmd)
2979081ff398SHannes Reinecke 				cmd_blk = scsi_cmd_priv(scmd);
2980081ff398SHannes Reinecke 		}
2981081ff398SHannes Reinecke 		if (cmd_blk)
2982081ff398SHannes Reinecke 			cmd_blk->status = next_stat_mbox->status;
2983081ff398SHannes Reinecke 		else
2984081ff398SHannes Reinecke 			dev_err(&cb->pdev->dev,
2985081ff398SHannes Reinecke 				"Unhandled command completion %d\n", id);
2986081ff398SHannes Reinecke 
2987081ff398SHannes Reinecke 		memset(next_stat_mbox, 0, sizeof(struct myrb_stat_mbox));
2988081ff398SHannes Reinecke 		if (++next_stat_mbox > cb->last_stat_mbox)
2989081ff398SHannes Reinecke 			next_stat_mbox = cb->first_stat_mbox;
2990081ff398SHannes Reinecke 
2991081ff398SHannes Reinecke 		if (id < 3)
2992081ff398SHannes Reinecke 			myrb_handle_cmdblk(cb, cmd_blk);
2993081ff398SHannes Reinecke 		else
2994081ff398SHannes Reinecke 			myrb_handle_scsi(cb, cmd_blk, scmd);
2995081ff398SHannes Reinecke 	}
2996081ff398SHannes Reinecke 	cb->next_stat_mbox = next_stat_mbox;
2997081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
2998081ff398SHannes Reinecke 	return IRQ_HANDLED;
2999081ff398SHannes Reinecke }
3000081ff398SHannes Reinecke 
3001182ad87cSShixin Liu static struct myrb_privdata DAC960_PG_privdata = {
3002081ff398SHannes Reinecke 	.hw_init =	DAC960_PG_hw_init,
3003081ff398SHannes Reinecke 	.irq_handler =	DAC960_PG_intr_handler,
3004081ff398SHannes Reinecke 	.mmio_size =	DAC960_PG_mmio_size,
3005081ff398SHannes Reinecke };
3006081ff398SHannes Reinecke 
3007081ff398SHannes Reinecke 
3008081ff398SHannes Reinecke /*
3009081ff398SHannes Reinecke  * DAC960 PD Series Controllers
3010081ff398SHannes Reinecke  */
3011081ff398SHannes Reinecke 
DAC960_PD_hw_mbox_new_cmd(void __iomem * base)3012081ff398SHannes Reinecke static inline void DAC960_PD_hw_mbox_new_cmd(void __iomem *base)
3013081ff398SHannes Reinecke {
3014081ff398SHannes Reinecke 	writeb(DAC960_PD_IDB_HWMBOX_NEW_CMD, base + DAC960_PD_IDB_OFFSET);
3015081ff398SHannes Reinecke }
3016081ff398SHannes Reinecke 
DAC960_PD_ack_hw_mbox_status(void __iomem * base)3017081ff398SHannes Reinecke static inline void DAC960_PD_ack_hw_mbox_status(void __iomem *base)
3018081ff398SHannes Reinecke {
3019081ff398SHannes Reinecke 	writeb(DAC960_PD_IDB_HWMBOX_ACK_STS, base + DAC960_PD_IDB_OFFSET);
3020081ff398SHannes Reinecke }
3021081ff398SHannes Reinecke 
DAC960_PD_reset_ctrl(void __iomem * base)3022081ff398SHannes Reinecke static inline void DAC960_PD_reset_ctrl(void __iomem *base)
3023081ff398SHannes Reinecke {
3024081ff398SHannes Reinecke 	writeb(DAC960_PD_IDB_CTRL_RESET, base + DAC960_PD_IDB_OFFSET);
3025081ff398SHannes Reinecke }
3026081ff398SHannes Reinecke 
DAC960_PD_hw_mbox_is_full(void __iomem * base)3027081ff398SHannes Reinecke static inline bool DAC960_PD_hw_mbox_is_full(void __iomem *base)
3028081ff398SHannes Reinecke {
3029081ff398SHannes Reinecke 	unsigned char idb = readb(base + DAC960_PD_IDB_OFFSET);
3030081ff398SHannes Reinecke 
3031081ff398SHannes Reinecke 	return idb & DAC960_PD_IDB_HWMBOX_FULL;
3032081ff398SHannes Reinecke }
3033081ff398SHannes Reinecke 
DAC960_PD_init_in_progress(void __iomem * base)3034081ff398SHannes Reinecke static inline bool DAC960_PD_init_in_progress(void __iomem *base)
3035081ff398SHannes Reinecke {
3036081ff398SHannes Reinecke 	unsigned char idb = readb(base + DAC960_PD_IDB_OFFSET);
3037081ff398SHannes Reinecke 
3038081ff398SHannes Reinecke 	return idb & DAC960_PD_IDB_INIT_IN_PROGRESS;
3039081ff398SHannes Reinecke }
3040081ff398SHannes Reinecke 
DAC960_PD_ack_intr(void __iomem * base)3041081ff398SHannes Reinecke static inline void DAC960_PD_ack_intr(void __iomem *base)
3042081ff398SHannes Reinecke {
3043081ff398SHannes Reinecke 	writeb(DAC960_PD_ODB_HWMBOX_ACK_IRQ, base + DAC960_PD_ODB_OFFSET);
3044081ff398SHannes Reinecke }
3045081ff398SHannes Reinecke 
DAC960_PD_hw_mbox_status_available(void __iomem * base)3046081ff398SHannes Reinecke static inline bool DAC960_PD_hw_mbox_status_available(void __iomem *base)
3047081ff398SHannes Reinecke {
3048081ff398SHannes Reinecke 	unsigned char odb = readb(base + DAC960_PD_ODB_OFFSET);
3049081ff398SHannes Reinecke 
3050081ff398SHannes Reinecke 	return odb & DAC960_PD_ODB_HWMBOX_STS_AVAIL;
3051081ff398SHannes Reinecke }
3052081ff398SHannes Reinecke 
DAC960_PD_enable_intr(void __iomem * base)3053081ff398SHannes Reinecke static inline void DAC960_PD_enable_intr(void __iomem *base)
3054081ff398SHannes Reinecke {
3055081ff398SHannes Reinecke 	writeb(DAC960_PD_IRQMASK_ENABLE_IRQ, base + DAC960_PD_IRQEN_OFFSET);
3056081ff398SHannes Reinecke }
3057081ff398SHannes Reinecke 
DAC960_PD_disable_intr(void __iomem * base)3058081ff398SHannes Reinecke static inline void DAC960_PD_disable_intr(void __iomem *base)
3059081ff398SHannes Reinecke {
3060081ff398SHannes Reinecke 	writeb(0, base + DAC960_PD_IRQEN_OFFSET);
3061081ff398SHannes Reinecke }
3062081ff398SHannes Reinecke 
DAC960_PD_write_cmd_mbox(void __iomem * base,union myrb_cmd_mbox * mbox)3063081ff398SHannes Reinecke static inline void DAC960_PD_write_cmd_mbox(void __iomem *base,
3064081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox)
3065081ff398SHannes Reinecke {
3066081ff398SHannes Reinecke 	writel(mbox->words[0], base + DAC960_PD_CMDOP_OFFSET);
3067081ff398SHannes Reinecke 	writel(mbox->words[1], base + DAC960_PD_MBOX4_OFFSET);
3068081ff398SHannes Reinecke 	writel(mbox->words[2], base + DAC960_PD_MBOX8_OFFSET);
3069081ff398SHannes Reinecke 	writeb(mbox->bytes[12], base + DAC960_PD_MBOX12_OFFSET);
3070081ff398SHannes Reinecke }
3071081ff398SHannes Reinecke 
3072081ff398SHannes Reinecke static inline unsigned char
DAC960_PD_read_status_cmd_ident(void __iomem * base)3073081ff398SHannes Reinecke DAC960_PD_read_status_cmd_ident(void __iomem *base)
3074081ff398SHannes Reinecke {
3075081ff398SHannes Reinecke 	return readb(base + DAC960_PD_STSID_OFFSET);
3076081ff398SHannes Reinecke }
3077081ff398SHannes Reinecke 
3078081ff398SHannes Reinecke static inline unsigned short
DAC960_PD_read_status(void __iomem * base)3079081ff398SHannes Reinecke DAC960_PD_read_status(void __iomem *base)
3080081ff398SHannes Reinecke {
3081081ff398SHannes Reinecke 	return readw(base + DAC960_PD_STS_OFFSET);
3082081ff398SHannes Reinecke }
3083081ff398SHannes Reinecke 
3084081ff398SHannes Reinecke static inline bool
DAC960_PD_read_error_status(void __iomem * base,unsigned char * error,unsigned char * param0,unsigned char * param1)3085081ff398SHannes Reinecke DAC960_PD_read_error_status(void __iomem *base, unsigned char *error,
3086081ff398SHannes Reinecke 		unsigned char *param0, unsigned char *param1)
3087081ff398SHannes Reinecke {
3088081ff398SHannes Reinecke 	unsigned char errsts = readb(base + DAC960_PD_ERRSTS_OFFSET);
3089081ff398SHannes Reinecke 
3090081ff398SHannes Reinecke 	if (!(errsts & DAC960_PD_ERRSTS_PENDING))
3091081ff398SHannes Reinecke 		return false;
3092081ff398SHannes Reinecke 	errsts &= ~DAC960_PD_ERRSTS_PENDING;
3093081ff398SHannes Reinecke 	*error = errsts;
3094081ff398SHannes Reinecke 	*param0 = readb(base + DAC960_PD_CMDOP_OFFSET);
3095081ff398SHannes Reinecke 	*param1 = readb(base + DAC960_PD_CMDID_OFFSET);
3096081ff398SHannes Reinecke 	writeb(0, base + DAC960_PD_ERRSTS_OFFSET);
3097081ff398SHannes Reinecke 	return true;
3098081ff398SHannes Reinecke }
3099081ff398SHannes Reinecke 
DAC960_PD_qcmd(struct myrb_hba * cb,struct myrb_cmdblk * cmd_blk)3100081ff398SHannes Reinecke static void DAC960_PD_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
3101081ff398SHannes Reinecke {
3102081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
3103081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
3104081ff398SHannes Reinecke 
3105081ff398SHannes Reinecke 	while (DAC960_PD_hw_mbox_is_full(base))
3106081ff398SHannes Reinecke 		udelay(1);
3107081ff398SHannes Reinecke 	DAC960_PD_write_cmd_mbox(base, mbox);
3108081ff398SHannes Reinecke 	DAC960_PD_hw_mbox_new_cmd(base);
3109081ff398SHannes Reinecke }
3110081ff398SHannes Reinecke 
DAC960_PD_hw_init(struct pci_dev * pdev,struct myrb_hba * cb,void __iomem * base)3111081ff398SHannes Reinecke static int DAC960_PD_hw_init(struct pci_dev *pdev,
3112081ff398SHannes Reinecke 		struct myrb_hba *cb, void __iomem *base)
3113081ff398SHannes Reinecke {
3114081ff398SHannes Reinecke 	int timeout = 0;
3115081ff398SHannes Reinecke 	unsigned char error, parm0, parm1;
3116081ff398SHannes Reinecke 
3117081ff398SHannes Reinecke 	if (!request_region(cb->io_addr, 0x80, "myrb")) {
3118081ff398SHannes Reinecke 		dev_err(&pdev->dev, "IO port 0x%lx busy\n",
3119081ff398SHannes Reinecke 			(unsigned long)cb->io_addr);
3120081ff398SHannes Reinecke 		return -EBUSY;
3121081ff398SHannes Reinecke 	}
3122081ff398SHannes Reinecke 	DAC960_PD_disable_intr(base);
3123081ff398SHannes Reinecke 	DAC960_PD_ack_hw_mbox_status(base);
3124081ff398SHannes Reinecke 	udelay(1000);
3125081ff398SHannes Reinecke 	while (DAC960_PD_init_in_progress(base) &&
3126081ff398SHannes Reinecke 	       timeout < MYRB_MAILBOX_TIMEOUT) {
3127081ff398SHannes Reinecke 		if (DAC960_PD_read_error_status(base, &error,
3128081ff398SHannes Reinecke 					      &parm0, &parm1) &&
3129081ff398SHannes Reinecke 		    myrb_err_status(cb, error, parm0, parm1))
3130081ff398SHannes Reinecke 			return -EIO;
3131081ff398SHannes Reinecke 		udelay(10);
3132081ff398SHannes Reinecke 		timeout++;
3133081ff398SHannes Reinecke 	}
3134081ff398SHannes Reinecke 	if (timeout == MYRB_MAILBOX_TIMEOUT) {
3135081ff398SHannes Reinecke 		dev_err(&pdev->dev,
3136081ff398SHannes Reinecke 			"Timeout waiting for Controller Initialisation\n");
3137081ff398SHannes Reinecke 		return -ETIMEDOUT;
3138081ff398SHannes Reinecke 	}
3139081ff398SHannes Reinecke 	if (!myrb_enable_mmio(cb, NULL)) {
3140081ff398SHannes Reinecke 		dev_err(&pdev->dev,
3141081ff398SHannes Reinecke 			"Unable to Enable Memory Mailbox Interface\n");
3142081ff398SHannes Reinecke 		DAC960_PD_reset_ctrl(base);
3143081ff398SHannes Reinecke 		return -ENODEV;
3144081ff398SHannes Reinecke 	}
3145081ff398SHannes Reinecke 	DAC960_PD_enable_intr(base);
3146081ff398SHannes Reinecke 	cb->qcmd = DAC960_PD_qcmd;
3147081ff398SHannes Reinecke 	cb->disable_intr = DAC960_PD_disable_intr;
3148081ff398SHannes Reinecke 	cb->reset = DAC960_PD_reset_ctrl;
3149081ff398SHannes Reinecke 
3150081ff398SHannes Reinecke 	return 0;
3151081ff398SHannes Reinecke }
3152081ff398SHannes Reinecke 
DAC960_PD_intr_handler(int irq,void * arg)3153081ff398SHannes Reinecke static irqreturn_t DAC960_PD_intr_handler(int irq, void *arg)
3154081ff398SHannes Reinecke {
3155081ff398SHannes Reinecke 	struct myrb_hba *cb = arg;
3156081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
3157081ff398SHannes Reinecke 	unsigned long flags;
3158081ff398SHannes Reinecke 
3159081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
3160081ff398SHannes Reinecke 	while (DAC960_PD_hw_mbox_status_available(base)) {
3161081ff398SHannes Reinecke 		unsigned char id = DAC960_PD_read_status_cmd_ident(base);
3162081ff398SHannes Reinecke 		struct scsi_cmnd *scmd = NULL;
3163081ff398SHannes Reinecke 		struct myrb_cmdblk *cmd_blk = NULL;
3164081ff398SHannes Reinecke 
3165081ff398SHannes Reinecke 		if (id == MYRB_DCMD_TAG)
3166081ff398SHannes Reinecke 			cmd_blk = &cb->dcmd_blk;
3167081ff398SHannes Reinecke 		else if (id == MYRB_MCMD_TAG)
3168081ff398SHannes Reinecke 			cmd_blk = &cb->mcmd_blk;
3169081ff398SHannes Reinecke 		else {
3170081ff398SHannes Reinecke 			scmd = scsi_host_find_tag(cb->host, id - 3);
3171081ff398SHannes Reinecke 			if (scmd)
3172081ff398SHannes Reinecke 				cmd_blk = scsi_cmd_priv(scmd);
3173081ff398SHannes Reinecke 		}
3174081ff398SHannes Reinecke 		if (cmd_blk)
3175081ff398SHannes Reinecke 			cmd_blk->status = DAC960_PD_read_status(base);
3176081ff398SHannes Reinecke 		else
3177081ff398SHannes Reinecke 			dev_err(&cb->pdev->dev,
3178081ff398SHannes Reinecke 				"Unhandled command completion %d\n", id);
3179081ff398SHannes Reinecke 
3180081ff398SHannes Reinecke 		DAC960_PD_ack_intr(base);
3181081ff398SHannes Reinecke 		DAC960_PD_ack_hw_mbox_status(base);
3182081ff398SHannes Reinecke 
3183081ff398SHannes Reinecke 		if (id < 3)
3184081ff398SHannes Reinecke 			myrb_handle_cmdblk(cb, cmd_blk);
3185081ff398SHannes Reinecke 		else
3186081ff398SHannes Reinecke 			myrb_handle_scsi(cb, cmd_blk, scmd);
3187081ff398SHannes Reinecke 	}
3188081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
3189081ff398SHannes Reinecke 	return IRQ_HANDLED;
3190081ff398SHannes Reinecke }
3191081ff398SHannes Reinecke 
3192182ad87cSShixin Liu static struct myrb_privdata DAC960_PD_privdata = {
3193081ff398SHannes Reinecke 	.hw_init =	DAC960_PD_hw_init,
3194081ff398SHannes Reinecke 	.irq_handler =	DAC960_PD_intr_handler,
3195081ff398SHannes Reinecke 	.mmio_size =	DAC960_PD_mmio_size,
3196081ff398SHannes Reinecke };
3197081ff398SHannes Reinecke 
3198081ff398SHannes Reinecke 
3199081ff398SHannes Reinecke /*
3200081ff398SHannes Reinecke  * DAC960 P Series Controllers
3201081ff398SHannes Reinecke  *
3202081ff398SHannes Reinecke  * Similar to the DAC960 PD Series Controllers, but some commands have
3203081ff398SHannes Reinecke  * to be translated.
3204081ff398SHannes Reinecke  */
3205081ff398SHannes Reinecke 
myrb_translate_enquiry(void * enq)3206081ff398SHannes Reinecke static inline void myrb_translate_enquiry(void *enq)
3207081ff398SHannes Reinecke {
3208081ff398SHannes Reinecke 	memcpy(enq + 132, enq + 36, 64);
3209081ff398SHannes Reinecke 	memset(enq + 36, 0, 96);
3210081ff398SHannes Reinecke }
3211081ff398SHannes Reinecke 
myrb_translate_devstate(void * state)3212081ff398SHannes Reinecke static inline void myrb_translate_devstate(void *state)
3213081ff398SHannes Reinecke {
3214081ff398SHannes Reinecke 	memcpy(state + 2, state + 3, 1);
3215081ff398SHannes Reinecke 	memmove(state + 4, state + 5, 2);
3216081ff398SHannes Reinecke 	memmove(state + 6, state + 8, 4);
3217081ff398SHannes Reinecke }
3218081ff398SHannes Reinecke 
myrb_translate_to_rw_command(struct myrb_cmdblk * cmd_blk)3219081ff398SHannes Reinecke static inline void myrb_translate_to_rw_command(struct myrb_cmdblk *cmd_blk)
3220081ff398SHannes Reinecke {
3221081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
3222081ff398SHannes Reinecke 	int ldev_num = mbox->type5.ld.ldev_num;
3223081ff398SHannes Reinecke 
3224081ff398SHannes Reinecke 	mbox->bytes[3] &= 0x7;
3225081ff398SHannes Reinecke 	mbox->bytes[3] |= mbox->bytes[7] << 6;
3226081ff398SHannes Reinecke 	mbox->bytes[7] = ldev_num;
3227081ff398SHannes Reinecke }
3228081ff398SHannes Reinecke 
myrb_translate_from_rw_command(struct myrb_cmdblk * cmd_blk)3229081ff398SHannes Reinecke static inline void myrb_translate_from_rw_command(struct myrb_cmdblk *cmd_blk)
3230081ff398SHannes Reinecke {
3231081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
3232081ff398SHannes Reinecke 	int ldev_num = mbox->bytes[7];
3233081ff398SHannes Reinecke 
3234081ff398SHannes Reinecke 	mbox->bytes[7] = mbox->bytes[3] >> 6;
3235081ff398SHannes Reinecke 	mbox->bytes[3] &= 0x7;
3236081ff398SHannes Reinecke 	mbox->bytes[3] |= ldev_num << 3;
3237081ff398SHannes Reinecke }
3238081ff398SHannes Reinecke 
DAC960_P_qcmd(struct myrb_hba * cb,struct myrb_cmdblk * cmd_blk)3239081ff398SHannes Reinecke static void DAC960_P_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
3240081ff398SHannes Reinecke {
3241081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
3242081ff398SHannes Reinecke 	union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
3243081ff398SHannes Reinecke 
3244081ff398SHannes Reinecke 	switch (mbox->common.opcode) {
3245081ff398SHannes Reinecke 	case MYRB_CMD_ENQUIRY:
3246081ff398SHannes Reinecke 		mbox->common.opcode = MYRB_CMD_ENQUIRY_OLD;
3247081ff398SHannes Reinecke 		break;
3248081ff398SHannes Reinecke 	case MYRB_CMD_GET_DEVICE_STATE:
3249081ff398SHannes Reinecke 		mbox->common.opcode = MYRB_CMD_GET_DEVICE_STATE_OLD;
3250081ff398SHannes Reinecke 		break;
3251081ff398SHannes Reinecke 	case MYRB_CMD_READ:
3252081ff398SHannes Reinecke 		mbox->common.opcode = MYRB_CMD_READ_OLD;
3253081ff398SHannes Reinecke 		myrb_translate_to_rw_command(cmd_blk);
3254081ff398SHannes Reinecke 		break;
3255081ff398SHannes Reinecke 	case MYRB_CMD_WRITE:
3256081ff398SHannes Reinecke 		mbox->common.opcode = MYRB_CMD_WRITE_OLD;
3257081ff398SHannes Reinecke 		myrb_translate_to_rw_command(cmd_blk);
3258081ff398SHannes Reinecke 		break;
3259081ff398SHannes Reinecke 	case MYRB_CMD_READ_SG:
3260081ff398SHannes Reinecke 		mbox->common.opcode = MYRB_CMD_READ_SG_OLD;
3261081ff398SHannes Reinecke 		myrb_translate_to_rw_command(cmd_blk);
3262081ff398SHannes Reinecke 		break;
3263081ff398SHannes Reinecke 	case MYRB_CMD_WRITE_SG:
3264081ff398SHannes Reinecke 		mbox->common.opcode = MYRB_CMD_WRITE_SG_OLD;
3265081ff398SHannes Reinecke 		myrb_translate_to_rw_command(cmd_blk);
3266081ff398SHannes Reinecke 		break;
3267081ff398SHannes Reinecke 	default:
3268081ff398SHannes Reinecke 		break;
3269081ff398SHannes Reinecke 	}
3270081ff398SHannes Reinecke 	while (DAC960_PD_hw_mbox_is_full(base))
3271081ff398SHannes Reinecke 		udelay(1);
3272081ff398SHannes Reinecke 	DAC960_PD_write_cmd_mbox(base, mbox);
3273081ff398SHannes Reinecke 	DAC960_PD_hw_mbox_new_cmd(base);
3274081ff398SHannes Reinecke }
3275081ff398SHannes Reinecke 
3276081ff398SHannes Reinecke 
DAC960_P_hw_init(struct pci_dev * pdev,struct myrb_hba * cb,void __iomem * base)3277081ff398SHannes Reinecke static int DAC960_P_hw_init(struct pci_dev *pdev,
3278081ff398SHannes Reinecke 		struct myrb_hba *cb, void __iomem *base)
3279081ff398SHannes Reinecke {
3280081ff398SHannes Reinecke 	int timeout = 0;
3281081ff398SHannes Reinecke 	unsigned char error, parm0, parm1;
3282081ff398SHannes Reinecke 
3283081ff398SHannes Reinecke 	if (!request_region(cb->io_addr, 0x80, "myrb")) {
3284081ff398SHannes Reinecke 		dev_err(&pdev->dev, "IO port 0x%lx busy\n",
3285081ff398SHannes Reinecke 			(unsigned long)cb->io_addr);
3286081ff398SHannes Reinecke 		return -EBUSY;
3287081ff398SHannes Reinecke 	}
3288081ff398SHannes Reinecke 	DAC960_PD_disable_intr(base);
3289081ff398SHannes Reinecke 	DAC960_PD_ack_hw_mbox_status(base);
3290081ff398SHannes Reinecke 	udelay(1000);
3291081ff398SHannes Reinecke 	while (DAC960_PD_init_in_progress(base) &&
3292081ff398SHannes Reinecke 	       timeout < MYRB_MAILBOX_TIMEOUT) {
3293081ff398SHannes Reinecke 		if (DAC960_PD_read_error_status(base, &error,
3294081ff398SHannes Reinecke 						&parm0, &parm1) &&
3295081ff398SHannes Reinecke 		    myrb_err_status(cb, error, parm0, parm1))
3296081ff398SHannes Reinecke 			return -EAGAIN;
3297081ff398SHannes Reinecke 		udelay(10);
3298081ff398SHannes Reinecke 		timeout++;
3299081ff398SHannes Reinecke 	}
3300081ff398SHannes Reinecke 	if (timeout == MYRB_MAILBOX_TIMEOUT) {
3301081ff398SHannes Reinecke 		dev_err(&pdev->dev,
3302081ff398SHannes Reinecke 			"Timeout waiting for Controller Initialisation\n");
3303081ff398SHannes Reinecke 		return -ETIMEDOUT;
3304081ff398SHannes Reinecke 	}
3305081ff398SHannes Reinecke 	if (!myrb_enable_mmio(cb, NULL)) {
3306081ff398SHannes Reinecke 		dev_err(&pdev->dev,
3307081ff398SHannes Reinecke 			"Unable to allocate DMA mapped memory\n");
3308081ff398SHannes Reinecke 		DAC960_PD_reset_ctrl(base);
3309081ff398SHannes Reinecke 		return -ETIMEDOUT;
3310081ff398SHannes Reinecke 	}
3311081ff398SHannes Reinecke 	DAC960_PD_enable_intr(base);
3312081ff398SHannes Reinecke 	cb->qcmd = DAC960_P_qcmd;
3313081ff398SHannes Reinecke 	cb->disable_intr = DAC960_PD_disable_intr;
3314081ff398SHannes Reinecke 	cb->reset = DAC960_PD_reset_ctrl;
3315081ff398SHannes Reinecke 
3316081ff398SHannes Reinecke 	return 0;
3317081ff398SHannes Reinecke }
3318081ff398SHannes Reinecke 
DAC960_P_intr_handler(int irq,void * arg)3319081ff398SHannes Reinecke static irqreturn_t DAC960_P_intr_handler(int irq, void *arg)
3320081ff398SHannes Reinecke {
3321081ff398SHannes Reinecke 	struct myrb_hba *cb = arg;
3322081ff398SHannes Reinecke 	void __iomem *base = cb->io_base;
3323081ff398SHannes Reinecke 	unsigned long flags;
3324081ff398SHannes Reinecke 
3325081ff398SHannes Reinecke 	spin_lock_irqsave(&cb->queue_lock, flags);
3326081ff398SHannes Reinecke 	while (DAC960_PD_hw_mbox_status_available(base)) {
3327081ff398SHannes Reinecke 		unsigned char id = DAC960_PD_read_status_cmd_ident(base);
3328081ff398SHannes Reinecke 		struct scsi_cmnd *scmd = NULL;
3329081ff398SHannes Reinecke 		struct myrb_cmdblk *cmd_blk = NULL;
3330081ff398SHannes Reinecke 		union myrb_cmd_mbox *mbox;
3331081ff398SHannes Reinecke 		enum myrb_cmd_opcode op;
3332081ff398SHannes Reinecke 
3333081ff398SHannes Reinecke 
3334081ff398SHannes Reinecke 		if (id == MYRB_DCMD_TAG)
3335081ff398SHannes Reinecke 			cmd_blk = &cb->dcmd_blk;
3336081ff398SHannes Reinecke 		else if (id == MYRB_MCMD_TAG)
3337081ff398SHannes Reinecke 			cmd_blk = &cb->mcmd_blk;
3338081ff398SHannes Reinecke 		else {
3339081ff398SHannes Reinecke 			scmd = scsi_host_find_tag(cb->host, id - 3);
3340081ff398SHannes Reinecke 			if (scmd)
3341081ff398SHannes Reinecke 				cmd_blk = scsi_cmd_priv(scmd);
3342081ff398SHannes Reinecke 		}
3343081ff398SHannes Reinecke 		if (cmd_blk)
3344081ff398SHannes Reinecke 			cmd_blk->status = DAC960_PD_read_status(base);
3345081ff398SHannes Reinecke 		else
3346081ff398SHannes Reinecke 			dev_err(&cb->pdev->dev,
3347081ff398SHannes Reinecke 				"Unhandled command completion %d\n", id);
3348081ff398SHannes Reinecke 
3349081ff398SHannes Reinecke 		DAC960_PD_ack_intr(base);
3350081ff398SHannes Reinecke 		DAC960_PD_ack_hw_mbox_status(base);
3351081ff398SHannes Reinecke 
3352081ff398SHannes Reinecke 		if (!cmd_blk)
3353081ff398SHannes Reinecke 			continue;
3354081ff398SHannes Reinecke 
3355081ff398SHannes Reinecke 		mbox = &cmd_blk->mbox;
3356081ff398SHannes Reinecke 		op = mbox->common.opcode;
3357081ff398SHannes Reinecke 		switch (op) {
3358081ff398SHannes Reinecke 		case MYRB_CMD_ENQUIRY_OLD:
3359081ff398SHannes Reinecke 			mbox->common.opcode = MYRB_CMD_ENQUIRY;
3360081ff398SHannes Reinecke 			myrb_translate_enquiry(cb->enquiry);
3361081ff398SHannes Reinecke 			break;
3362081ff398SHannes Reinecke 		case MYRB_CMD_READ_OLD:
3363081ff398SHannes Reinecke 			mbox->common.opcode = MYRB_CMD_READ;
3364081ff398SHannes Reinecke 			myrb_translate_from_rw_command(cmd_blk);
3365081ff398SHannes Reinecke 			break;
3366081ff398SHannes Reinecke 		case MYRB_CMD_WRITE_OLD:
3367081ff398SHannes Reinecke 			mbox->common.opcode = MYRB_CMD_WRITE;
3368081ff398SHannes Reinecke 			myrb_translate_from_rw_command(cmd_blk);
3369081ff398SHannes Reinecke 			break;
3370081ff398SHannes Reinecke 		case MYRB_CMD_READ_SG_OLD:
3371081ff398SHannes Reinecke 			mbox->common.opcode = MYRB_CMD_READ_SG;
3372081ff398SHannes Reinecke 			myrb_translate_from_rw_command(cmd_blk);
3373081ff398SHannes Reinecke 			break;
3374081ff398SHannes Reinecke 		case MYRB_CMD_WRITE_SG_OLD:
3375081ff398SHannes Reinecke 			mbox->common.opcode = MYRB_CMD_WRITE_SG;
3376081ff398SHannes Reinecke 			myrb_translate_from_rw_command(cmd_blk);
3377081ff398SHannes Reinecke 			break;
3378081ff398SHannes Reinecke 		default:
3379081ff398SHannes Reinecke 			break;
3380081ff398SHannes Reinecke 		}
3381081ff398SHannes Reinecke 		if (id < 3)
3382081ff398SHannes Reinecke 			myrb_handle_cmdblk(cb, cmd_blk);
3383081ff398SHannes Reinecke 		else
3384081ff398SHannes Reinecke 			myrb_handle_scsi(cb, cmd_blk, scmd);
3385081ff398SHannes Reinecke 	}
3386081ff398SHannes Reinecke 	spin_unlock_irqrestore(&cb->queue_lock, flags);
3387081ff398SHannes Reinecke 	return IRQ_HANDLED;
3388081ff398SHannes Reinecke }
3389081ff398SHannes Reinecke 
3390182ad87cSShixin Liu static struct myrb_privdata DAC960_P_privdata = {
3391081ff398SHannes Reinecke 	.hw_init =	DAC960_P_hw_init,
3392081ff398SHannes Reinecke 	.irq_handler =	DAC960_P_intr_handler,
3393081ff398SHannes Reinecke 	.mmio_size =	DAC960_PD_mmio_size,
3394081ff398SHannes Reinecke };
3395081ff398SHannes Reinecke 
myrb_detect(struct pci_dev * pdev,const struct pci_device_id * entry)3396081ff398SHannes Reinecke static struct myrb_hba *myrb_detect(struct pci_dev *pdev,
3397081ff398SHannes Reinecke 		const struct pci_device_id *entry)
3398081ff398SHannes Reinecke {
3399081ff398SHannes Reinecke 	struct myrb_privdata *privdata =
3400081ff398SHannes Reinecke 		(struct myrb_privdata *)entry->driver_data;
3401081ff398SHannes Reinecke 	irq_handler_t irq_handler = privdata->irq_handler;
3402081ff398SHannes Reinecke 	unsigned int mmio_size = privdata->mmio_size;
3403081ff398SHannes Reinecke 	struct Scsi_Host *shost;
3404081ff398SHannes Reinecke 	struct myrb_hba *cb = NULL;
3405081ff398SHannes Reinecke 
3406081ff398SHannes Reinecke 	shost = scsi_host_alloc(&myrb_template, sizeof(struct myrb_hba));
3407081ff398SHannes Reinecke 	if (!shost) {
3408081ff398SHannes Reinecke 		dev_err(&pdev->dev, "Unable to allocate Controller\n");
3409081ff398SHannes Reinecke 		return NULL;
3410081ff398SHannes Reinecke 	}
3411081ff398SHannes Reinecke 	shost->max_cmd_len = 12;
3412081ff398SHannes Reinecke 	shost->max_lun = 256;
3413081ff398SHannes Reinecke 	cb = shost_priv(shost);
3414081ff398SHannes Reinecke 	mutex_init(&cb->dcmd_mutex);
3415081ff398SHannes Reinecke 	mutex_init(&cb->dma_mutex);
3416081ff398SHannes Reinecke 	cb->pdev = pdev;
3417f9f0a461SHannes Reinecke 	cb->host = shost;
3418081ff398SHannes Reinecke 
3419f9f0a461SHannes Reinecke 	if (pci_enable_device(pdev)) {
3420f9f0a461SHannes Reinecke 		dev_err(&pdev->dev, "Failed to enable PCI device\n");
3421f9f0a461SHannes Reinecke 		scsi_host_put(shost);
3422f9f0a461SHannes Reinecke 		return NULL;
3423f9f0a461SHannes Reinecke 	}
3424081ff398SHannes Reinecke 
3425081ff398SHannes Reinecke 	if (privdata->hw_init == DAC960_PD_hw_init ||
3426081ff398SHannes Reinecke 	    privdata->hw_init == DAC960_P_hw_init) {
3427081ff398SHannes Reinecke 		cb->io_addr = pci_resource_start(pdev, 0);
3428081ff398SHannes Reinecke 		cb->pci_addr = pci_resource_start(pdev, 1);
3429081ff398SHannes Reinecke 	} else
3430081ff398SHannes Reinecke 		cb->pci_addr = pci_resource_start(pdev, 0);
3431081ff398SHannes Reinecke 
3432081ff398SHannes Reinecke 	pci_set_drvdata(pdev, cb);
3433081ff398SHannes Reinecke 	spin_lock_init(&cb->queue_lock);
3434081ff398SHannes Reinecke 	if (mmio_size < PAGE_SIZE)
3435081ff398SHannes Reinecke 		mmio_size = PAGE_SIZE;
34364bdc0d67SChristoph Hellwig 	cb->mmio_base = ioremap(cb->pci_addr & PAGE_MASK, mmio_size);
3437081ff398SHannes Reinecke 	if (cb->mmio_base == NULL) {
3438081ff398SHannes Reinecke 		dev_err(&pdev->dev,
3439081ff398SHannes Reinecke 			"Unable to map Controller Register Window\n");
3440081ff398SHannes Reinecke 		goto failure;
3441081ff398SHannes Reinecke 	}
3442081ff398SHannes Reinecke 
3443081ff398SHannes Reinecke 	cb->io_base = cb->mmio_base + (cb->pci_addr & ~PAGE_MASK);
3444081ff398SHannes Reinecke 	if (privdata->hw_init(pdev, cb, cb->io_base))
3445081ff398SHannes Reinecke 		goto failure;
3446081ff398SHannes Reinecke 
3447081ff398SHannes Reinecke 	if (request_irq(pdev->irq, irq_handler, IRQF_SHARED, "myrb", cb) < 0) {
3448081ff398SHannes Reinecke 		dev_err(&pdev->dev,
3449081ff398SHannes Reinecke 			"Unable to acquire IRQ Channel %d\n", pdev->irq);
3450081ff398SHannes Reinecke 		goto failure;
3451081ff398SHannes Reinecke 	}
3452081ff398SHannes Reinecke 	cb->irq = pdev->irq;
3453081ff398SHannes Reinecke 	return cb;
3454081ff398SHannes Reinecke 
3455081ff398SHannes Reinecke failure:
3456081ff398SHannes Reinecke 	dev_err(&pdev->dev,
3457081ff398SHannes Reinecke 		"Failed to initialize Controller\n");
3458081ff398SHannes Reinecke 	myrb_cleanup(cb);
3459081ff398SHannes Reinecke 	return NULL;
3460081ff398SHannes Reinecke }
3461081ff398SHannes Reinecke 
myrb_probe(struct pci_dev * dev,const struct pci_device_id * entry)3462081ff398SHannes Reinecke static int myrb_probe(struct pci_dev *dev, const struct pci_device_id *entry)
3463081ff398SHannes Reinecke {
3464081ff398SHannes Reinecke 	struct myrb_hba *cb;
3465081ff398SHannes Reinecke 	int ret;
3466081ff398SHannes Reinecke 
3467081ff398SHannes Reinecke 	cb = myrb_detect(dev, entry);
3468081ff398SHannes Reinecke 	if (!cb)
3469081ff398SHannes Reinecke 		return -ENODEV;
3470081ff398SHannes Reinecke 
3471081ff398SHannes Reinecke 	ret = myrb_get_hba_config(cb);
3472081ff398SHannes Reinecke 	if (ret < 0) {
3473081ff398SHannes Reinecke 		myrb_cleanup(cb);
3474081ff398SHannes Reinecke 		return ret;
3475081ff398SHannes Reinecke 	}
3476081ff398SHannes Reinecke 
3477081ff398SHannes Reinecke 	if (!myrb_create_mempools(dev, cb)) {
3478081ff398SHannes Reinecke 		ret = -ENOMEM;
3479081ff398SHannes Reinecke 		goto failed;
3480081ff398SHannes Reinecke 	}
3481081ff398SHannes Reinecke 
3482081ff398SHannes Reinecke 	ret = scsi_add_host(cb->host, &dev->dev);
3483081ff398SHannes Reinecke 	if (ret) {
3484081ff398SHannes Reinecke 		dev_err(&dev->dev, "scsi_add_host failed with %d\n", ret);
3485081ff398SHannes Reinecke 		myrb_destroy_mempools(cb);
3486081ff398SHannes Reinecke 		goto failed;
3487081ff398SHannes Reinecke 	}
3488081ff398SHannes Reinecke 	scsi_scan_host(cb->host);
3489081ff398SHannes Reinecke 	return 0;
3490081ff398SHannes Reinecke failed:
3491081ff398SHannes Reinecke 	myrb_cleanup(cb);
3492081ff398SHannes Reinecke 	return ret;
3493081ff398SHannes Reinecke }
3494081ff398SHannes Reinecke 
3495081ff398SHannes Reinecke 
myrb_remove(struct pci_dev * pdev)3496081ff398SHannes Reinecke static void myrb_remove(struct pci_dev *pdev)
3497081ff398SHannes Reinecke {
3498081ff398SHannes Reinecke 	struct myrb_hba *cb = pci_get_drvdata(pdev);
3499081ff398SHannes Reinecke 
3500081ff398SHannes Reinecke 	shost_printk(KERN_NOTICE, cb->host, "Flushing Cache...");
3501081ff398SHannes Reinecke 	myrb_exec_type3(cb, MYRB_CMD_FLUSH, 0);
3502081ff398SHannes Reinecke 	myrb_cleanup(cb);
3503081ff398SHannes Reinecke 	myrb_destroy_mempools(cb);
3504081ff398SHannes Reinecke }
3505081ff398SHannes Reinecke 
3506081ff398SHannes Reinecke 
3507081ff398SHannes Reinecke static const struct pci_device_id myrb_id_table[] = {
3508081ff398SHannes Reinecke 	{
3509081ff398SHannes Reinecke 		PCI_DEVICE_SUB(PCI_VENDOR_ID_DEC,
3510081ff398SHannes Reinecke 			       PCI_DEVICE_ID_DEC_21285,
3511081ff398SHannes Reinecke 			       PCI_VENDOR_ID_MYLEX,
3512081ff398SHannes Reinecke 			       PCI_DEVICE_ID_MYLEX_DAC960_LA),
3513081ff398SHannes Reinecke 		.driver_data	= (unsigned long) &DAC960_LA_privdata,
3514081ff398SHannes Reinecke 	},
3515081ff398SHannes Reinecke 	{
3516081ff398SHannes Reinecke 		PCI_DEVICE_DATA(MYLEX, DAC960_PG, &DAC960_PG_privdata),
3517081ff398SHannes Reinecke 	},
3518081ff398SHannes Reinecke 	{
3519081ff398SHannes Reinecke 		PCI_DEVICE_DATA(MYLEX, DAC960_PD, &DAC960_PD_privdata),
3520081ff398SHannes Reinecke 	},
3521081ff398SHannes Reinecke 	{
3522081ff398SHannes Reinecke 		PCI_DEVICE_DATA(MYLEX, DAC960_P, &DAC960_P_privdata),
3523081ff398SHannes Reinecke 	},
3524081ff398SHannes Reinecke 	{0, },
3525081ff398SHannes Reinecke };
3526081ff398SHannes Reinecke 
3527081ff398SHannes Reinecke MODULE_DEVICE_TABLE(pci, myrb_id_table);
3528081ff398SHannes Reinecke 
3529081ff398SHannes Reinecke static struct pci_driver myrb_pci_driver = {
3530081ff398SHannes Reinecke 	.name		= "myrb",
3531081ff398SHannes Reinecke 	.id_table	= myrb_id_table,
3532081ff398SHannes Reinecke 	.probe		= myrb_probe,
3533081ff398SHannes Reinecke 	.remove		= myrb_remove,
3534081ff398SHannes Reinecke };
3535081ff398SHannes Reinecke 
myrb_init_module(void)3536081ff398SHannes Reinecke static int __init myrb_init_module(void)
3537081ff398SHannes Reinecke {
3538081ff398SHannes Reinecke 	int ret;
3539081ff398SHannes Reinecke 
3540081ff398SHannes Reinecke 	myrb_raid_template = raid_class_attach(&myrb_raid_functions);
3541081ff398SHannes Reinecke 	if (!myrb_raid_template)
3542081ff398SHannes Reinecke 		return -ENODEV;
3543081ff398SHannes Reinecke 
3544081ff398SHannes Reinecke 	ret = pci_register_driver(&myrb_pci_driver);
3545081ff398SHannes Reinecke 	if (ret)
3546081ff398SHannes Reinecke 		raid_class_release(myrb_raid_template);
3547081ff398SHannes Reinecke 
3548081ff398SHannes Reinecke 	return ret;
3549081ff398SHannes Reinecke }
3550081ff398SHannes Reinecke 
myrb_cleanup_module(void)3551081ff398SHannes Reinecke static void __exit myrb_cleanup_module(void)
3552081ff398SHannes Reinecke {
3553081ff398SHannes Reinecke 	pci_unregister_driver(&myrb_pci_driver);
3554081ff398SHannes Reinecke 	raid_class_release(myrb_raid_template);
3555081ff398SHannes Reinecke }
3556081ff398SHannes Reinecke 
3557081ff398SHannes Reinecke module_init(myrb_init_module);
3558081ff398SHannes Reinecke module_exit(myrb_cleanup_module);
3559081ff398SHannes Reinecke 
3560081ff398SHannes Reinecke MODULE_DESCRIPTION("Mylex DAC960/AcceleRAID/eXtremeRAID driver (Block interface)");
3561081ff398SHannes Reinecke MODULE_AUTHOR("Hannes Reinecke <hare@suse.com>");
3562081ff398SHannes Reinecke MODULE_LICENSE("GPL");
3563