File: /usr/src/linux/drivers/scsi/pluto.c

1     /* pluto.c: SparcSTORAGE Array SCSI host adapter driver.
2      *
3      * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
4      *
5      */
6     
7     #include <linux/kernel.h>
8     #include <linux/delay.h>
9     #include <linux/types.h>
10     #include <linux/string.h>
11     #include <linux/slab.h>
12     #include <linux/blk.h>
13     #include <linux/proc_fs.h>
14     #include <linux/stat.h>
15     #include <linux/init.h>
16     #include <linux/config.h>
17     #ifdef CONFIG_KMOD
18     #include <linux/kmod.h>
19     #endif
20     
21     #include <asm/irq.h>
22     
23     #include "scsi.h"
24     #include "hosts.h"
25     #include "../fc4/fcp_impl.h"
26     #include "pluto.h"
27     
28     #include <linux/module.h>
29     
30     /* #define PLUTO_DEBUG */
31     
32     #define pluto_printk printk ("PLUTO %s: ", fc->name); printk
33     
34     #ifdef PLUTO_DEBUG
35     #define PLD(x)  pluto_printk x;
36     #define PLND(x) printk ("PLUTO: "); printk x;
37     #else
38     #define PLD(x)
39     #define PLND(x)
40     #endif
41     
42     static struct ctrl_inquiry {
43     	struct Scsi_Host host;
44     	struct pluto pluto;
45     	Scsi_Cmnd cmd;
46     	char inquiry[256];
47     	fc_channel *fc;
48     } *fcs __initdata = { 0 };
49     static int fcscount __initdata = 0;
50     static atomic_t fcss __initdata = ATOMIC_INIT(0);
51     DECLARE_MUTEX_LOCKED(fc_sem);
52     
53     static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
54     
55     static void __init pluto_detect_timeout(unsigned long data)
56     {
57     	PLND(("Timeout\n"))
58     	up(&fc_sem);
59     }
60     
61     static void __init pluto_detect_done(Scsi_Cmnd *SCpnt)
62     {
63     	/* Do nothing */
64     }
65     
66     static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
67     {
68     	SCpnt->request.rq_status = RQ_SCSI_DONE;
69     	PLND(("Detect done %08lx\n", (long)SCpnt))
70     	if (atomic_dec_and_test (&fcss))
71     		up(&fc_sem);
72     }
73     
74     static void pluto_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist)
75     {
76     	Scsi_Device *device;
77     	
78     	for (device = devlist; device; device = device->next) {
79     		if (device->host != host) continue;
80     		if (device->tagged_supported)
81     			device->queue_depth = /* 254 */ 8;
82     		else
83     			device->queue_depth = 2;
84     	}
85     }
86     
87     /* Detect all SSAs attached to the machine.
88        To be fast, do it on all online FC channels at the same time. */
89     int __init pluto_detect(Scsi_Host_Template *tpnt)
90     {
91     	int i, retry, nplutos;
92     	fc_channel *fc;
93     	Scsi_Device dev;
94     	struct timer_list fc_timer = { function: pluto_detect_timeout };
95     
96     	tpnt->proc_name = "pluto";
97     	fcscount = 0;
98     	for_each_online_fc_channel(fc) {
99     		if (!fc->posmap)
100     			fcscount++;
101     	}
102     	PLND(("%d channels online\n", fcscount))
103     	if (!fcscount) {
104     #if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD)
105     		request_module("soc");
106     		
107     		for_each_online_fc_channel(fc) {
108     			if (!fc->posmap)
109     				fcscount++;
110     		}
111     		if (!fcscount)
112     #endif
113     			return 0;
114     	}
115     	fcs = (struct ctrl_inquiry *) kmalloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
116     	if (!fcs) {
117     		printk ("PLUTO: Not enough memory to probe\n");
118     		return 0;
119     	}
120     	
121     	memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
122     	memset (&dev, 0, sizeof(dev));
123     	atomic_set (&fcss, fcscount);
124     	
125     	i = 0;
126     	for_each_online_fc_channel(fc) {
127     		Scsi_Cmnd *SCpnt;
128     		struct Scsi_Host *host;
129     		struct pluto *pluto;
130     
131     		if (i == fcscount) break;
132     		if (fc->posmap) continue;
133     		
134     		PLD(("trying to find SSA\n"))
135     
136     		/* If this is already registered to some other SCSI host, then it cannot be pluto */
137     		if (fc->scsi_name[0]) continue;
138     		memcpy (fc->scsi_name, "SSA", 4);
139     		
140     		fcs[i].fc = fc;
141     		
142     		fc->can_queue = PLUTO_CAN_QUEUE;
143     		fc->rsp_size = 64;
144     		fc->encode_addr = pluto_encode_addr;
145     		
146     		fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
147     	
148     		SCpnt = &(fcs[i].cmd);
149     		host = &(fcs[i].host);
150     		pluto = (struct pluto *)host->hostdata;
151     		
152     		pluto->fc = fc;
153     	
154     		SCpnt->host = host;
155     		SCpnt->cmnd[0] = INQUIRY;
156     		SCpnt->cmnd[4] = 255;
157     		
158     		/* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */
159     		SCpnt->device = &dev;
160     		
161     		SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
162     	
163     		SCpnt->request.rq_status = RQ_SCSI_BUSY;
164     		
165     		SCpnt->done = pluto_detect_done;
166     		SCpnt->bufflen = 256;
167     		SCpnt->buffer = fcs[i].inquiry;
168     		SCpnt->request_bufflen = 256;
169     		SCpnt->request_buffer = fcs[i].inquiry;
170     		PLD(("set up %d %08lx\n", i, (long)SCpnt))
171     		i++;
172     	}
173     	
174     	for (retry = 0; retry < 5; retry++) {
175     		for (i = 0; i < fcscount; i++) {
176     			if (!fcs[i].fc) break;
177     			if (fcs[i].cmd.request.rq_status != RQ_SCSI_DONE) {
178     				disable_irq(fcs[i].fc->irq);
179     				PLND(("queuecommand %d %d\n", retry, i))
180     				fcp_scsi_queuecommand (&(fcs[i].cmd), 
181     					pluto_detect_scsi_done);
182     				enable_irq(fcs[i].fc->irq);
183     			}
184     		}
185     	    
186     		fc_timer.expires = jiffies + 10 * HZ;
187     		add_timer(&fc_timer);
188     		
189     		down(&fc_sem);
190     		PLND(("Woken up\n"))
191     		if (!atomic_read(&fcss))
192     			break; /* All fc channels have answered us */
193     	}
194     	del_timer_sync(&fc_timer);
195     
196     	PLND(("Finished search\n"))
197     	for (i = 0, nplutos = 0; i < fcscount; i++) {
198     		Scsi_Cmnd *SCpnt;
199     		
200     		if (!(fc = fcs[i].fc)) break;
201     	
202     		SCpnt = &(fcs[i].cmd);
203     		
204     		/* Let FC mid-level free allocated resources */
205     		SCpnt->done (SCpnt);
206     		
207     		if (!SCpnt->result) {
208     			struct pluto_inquiry *inq;
209     			struct pluto *pluto;
210     			struct Scsi_Host *host;
211     			
212     			inq = (struct pluto_inquiry *)fcs[i].inquiry;
213     
214     			if ((inq->dtype & 0x1f) == TYPE_PROCESSOR &&
215     			    !strncmp (inq->vendor_id, "SUN", 3) &&
216     			    !strncmp (inq->product_id, "SSA", 3)) {
217     				char *p;
218     				long *ages;
219     				
220     				ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
221     				if (!ages) continue;
222     				
223     				host = scsi_register (tpnt, sizeof (struct pluto));
224     				if(!host)
225     				{
226     					kfree(ages);
227     					continue;
228     				}
229     				
230     				nplutos++;
231     				
232     				if (fc->module) __MOD_INC_USE_COUNT(fc->module);
233     				
234     				pluto = (struct pluto *)host->hostdata;
235     				
236     				host->max_id = inq->targets;
237     				host->max_channel = inq->channels;
238     				host->irq = fc->irq;
239     
240     #ifdef __sparc_v9__
241     				host->unchecked_isa_dma = 1;
242     #endif
243     
244     				host->select_queue_depths = pluto_select_queue_depths;
245     
246     				fc->channels = inq->channels + 1;
247     				fc->targets = inq->targets;
248     				fc->ages = ages;
249     				memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
250     				
251     				pluto->fc = fc;
252     				memcpy (pluto->rev_str, inq->revision, 4);
253     				pluto->rev_str[4] = 0;
254     				p = strchr (pluto->rev_str, ' ');
255     				if (p) *p = 0;
256     				memcpy (pluto->fw_rev_str, inq->fw_revision, 4);
257     				pluto->fw_rev_str[4] = 0;
258     				p = strchr (pluto->fw_rev_str, ' ');
259     				if (p) *p = 0;
260     				memcpy (pluto->serial_str, inq->serial, 12);
261     				pluto->serial_str[12] = 0;
262     				p = strchr (pluto->serial_str, ' ');
263     				if (p) *p = 0;
264     				
265     				PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id))
266     			} else
267     				fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
268     		} else
269     			fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
270     	}
271     	kfree((char *)fcs);
272     	if (nplutos)
273     		printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos);
274     	return nplutos;
275     }
276     
277     int pluto_release(struct Scsi_Host *host)
278     {
279     	struct pluto *pluto = (struct pluto *)host->hostdata;
280     	fc_channel *fc = pluto->fc;
281     
282     	if (fc->module) __MOD_DEC_USE_COUNT(fc->module);
283     	
284     	fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
285     	PLND((" releasing pluto.\n"));
286     	kfree (fc->ages);
287     	PLND(("released pluto!\n"));
288     	return 0;
289     }
290     
291     const char *pluto_info(struct Scsi_Host *host)
292     {
293     	static char buf[128], *p;
294     	struct pluto *pluto = (struct pluto *) host->hostdata;
295     
296     	sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s",
297     		pluto->rev_str, pluto->fw_rev_str, pluto->serial_str,
298     		host->max_channel, host->max_id, pluto->fc->name);
299     #ifdef __sparc__
300     	p = strchr(buf, 0);
301     	sprintf(p, " PROM node %x", pluto->fc->dev->prom_node);
302     #endif	
303     	return buf;
304     }
305     
306     /* SSA uses this FC4S addressing:
307        switch (addr[0])
308        {
309        case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0
310        case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0
311        case 2: DISK GROUP - ???
312        }
313        
314        So that SCSI mid-layer can access to these, we reserve
315        channel 0 id 0 lun 0 for CONTROLLER
316        and channels 1 .. max_channel are normal single disks.
317      */
318     static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd)
319     {
320     	PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0))
321     	/* We don't support LUNs - neither does SSA :) */
322     	if (SCpnt->cmnd[1] & 0xe0) return -EINVAL;
323     	if (!SCpnt->channel) {
324     		if (SCpnt->target) return -EINVAL;
325     		memset (addr, 0, 4 * sizeof(u16));
326     	} else {
327     		addr[0] = 1;
328     		addr[1] = SCpnt->channel - 1;
329     		addr[2] = SCpnt->target;
330     		addr[3] = 0;
331     	}
332     	/* We're Point-to-Point, so target it to the default DID */
333     	fcmd->did = fc->did;
334     	PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3]))
335     	return 0;
336     }
337     
338     static Scsi_Host_Template driver_template = PLUTO;
339     
340     #include "scsi_module.c"
341     
342     EXPORT_NO_SYMBOLS;
343