at v2.6.14 8.9 kB view raw
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/blkdev.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 <scsi/scsi_host.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 42static 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; 49static int fcscount __initdata = 0; 50static atomic_t fcss __initdata = ATOMIC_INIT(0); 51DECLARE_MUTEX_LOCKED(fc_sem); 52 53static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); 54 55static void __init pluto_detect_timeout(unsigned long data) 56{ 57 PLND(("Timeout\n")) 58 up(&fc_sem); 59} 60 61static void __init pluto_detect_done(Scsi_Cmnd *SCpnt) 62{ 63 /* Do nothing */ 64} 65 66static 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 74int pluto_slave_configure(Scsi_Device *device) 75{ 76 int depth_to_use; 77 78 if (device->tagged_supported) 79 depth_to_use = /* 254 */ 8; 80 else 81 depth_to_use = 2; 82 83 scsi_adjust_queue_depth(device, 84 (device->tagged_supported ? 85 MSG_SIMPLE_TAG : 0), 86 depth_to_use); 87 88 return 0; 89} 90 91/* Detect all SSAs attached to the machine. 92 To be fast, do it on all online FC channels at the same time. */ 93int __init pluto_detect(Scsi_Host_Template *tpnt) 94{ 95 int i, retry, nplutos; 96 fc_channel *fc; 97 Scsi_Device dev; 98 DEFINE_TIMER(fc_timer, pluto_detect_timeout, 0, 0); 99 100 tpnt->proc_name = "pluto"; 101 fcscount = 0; 102 for_each_online_fc_channel(fc) { 103 if (!fc->posmap) 104 fcscount++; 105 } 106 PLND(("%d channels online\n", fcscount)) 107 if (!fcscount) { 108#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD) 109 request_module("soc"); 110 111 for_each_online_fc_channel(fc) { 112 if (!fc->posmap) 113 fcscount++; 114 } 115 if (!fcscount) 116#endif 117 return 0; 118 } 119 fcs = (struct ctrl_inquiry *) kmalloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA); 120 if (!fcs) { 121 printk ("PLUTO: Not enough memory to probe\n"); 122 return 0; 123 } 124 125 memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount); 126 memset (&dev, 0, sizeof(dev)); 127 atomic_set (&fcss, fcscount); 128 129 i = 0; 130 for_each_online_fc_channel(fc) { 131 Scsi_Cmnd *SCpnt; 132 struct Scsi_Host *host; 133 struct pluto *pluto; 134 135 if (i == fcscount) break; 136 if (fc->posmap) continue; 137 138 PLD(("trying to find SSA\n")) 139 140 /* If this is already registered to some other SCSI host, then it cannot be pluto */ 141 if (fc->scsi_name[0]) continue; 142 memcpy (fc->scsi_name, "SSA", 4); 143 144 fcs[i].fc = fc; 145 146 fc->can_queue = PLUTO_CAN_QUEUE; 147 fc->rsp_size = 64; 148 fc->encode_addr = pluto_encode_addr; 149 150 fc->fcp_register(fc, TYPE_SCSI_FCP, 0); 151 152 SCpnt = &(fcs[i].cmd); 153 host = &(fcs[i].host); 154 pluto = (struct pluto *)host->hostdata; 155 156 pluto->fc = fc; 157 158 SCpnt->cmnd[0] = INQUIRY; 159 SCpnt->cmnd[4] = 255; 160 161 /* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */ 162 SCpnt->device = &dev; 163 dev.host = host; 164 165 SCpnt->cmd_len = COMMAND_SIZE(INQUIRY); 166 167 SCpnt->request->rq_status = RQ_SCSI_BUSY; 168 169 SCpnt->done = pluto_detect_done; 170 SCpnt->bufflen = 256; 171 SCpnt->buffer = fcs[i].inquiry; 172 SCpnt->request_bufflen = 256; 173 SCpnt->request_buffer = fcs[i].inquiry; 174 PLD(("set up %d %08lx\n", i, (long)SCpnt)) 175 i++; 176 } 177 178 for (retry = 0; retry < 5; retry++) { 179 for (i = 0; i < fcscount; i++) { 180 if (!fcs[i].fc) break; 181 if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) { 182 disable_irq(fcs[i].fc->irq); 183 PLND(("queuecommand %d %d\n", retry, i)) 184 fcp_scsi_queuecommand (&(fcs[i].cmd), 185 pluto_detect_scsi_done); 186 enable_irq(fcs[i].fc->irq); 187 } 188 } 189 190 fc_timer.expires = jiffies + 10 * HZ; 191 add_timer(&fc_timer); 192 193 down(&fc_sem); 194 PLND(("Woken up\n")) 195 if (!atomic_read(&fcss)) 196 break; /* All fc channels have answered us */ 197 } 198 del_timer_sync(&fc_timer); 199 200 PLND(("Finished search\n")) 201 for (i = 0, nplutos = 0; i < fcscount; i++) { 202 Scsi_Cmnd *SCpnt; 203 204 if (!(fc = fcs[i].fc)) break; 205 206 SCpnt = &(fcs[i].cmd); 207 208 /* Let FC mid-level free allocated resources */ 209 SCpnt->done (SCpnt); 210 211 if (!SCpnt->result) { 212 struct pluto_inquiry *inq; 213 struct pluto *pluto; 214 struct Scsi_Host *host; 215 216 inq = (struct pluto_inquiry *)fcs[i].inquiry; 217 218 if ((inq->dtype & 0x1f) == TYPE_PROCESSOR && 219 !strncmp (inq->vendor_id, "SUN", 3) && 220 !strncmp (inq->product_id, "SSA", 3)) { 221 char *p; 222 long *ages; 223 224 ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL); 225 if (!ages) continue; 226 227 host = scsi_register (tpnt, sizeof (struct pluto)); 228 if(!host) 229 { 230 kfree(ages); 231 continue; 232 } 233 234 if (!try_module_get(fc->module)) { 235 kfree(ages); 236 scsi_unregister(host); 237 continue; 238 } 239 240 nplutos++; 241 242 pluto = (struct pluto *)host->hostdata; 243 244 host->max_id = inq->targets; 245 host->max_channel = inq->channels; 246 host->irq = fc->irq; 247 248 fc->channels = inq->channels + 1; 249 fc->targets = inq->targets; 250 fc->ages = ages; 251 memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long)); 252 253 pluto->fc = fc; 254 memcpy (pluto->rev_str, inq->revision, 4); 255 pluto->rev_str[4] = 0; 256 p = strchr (pluto->rev_str, ' '); 257 if (p) *p = 0; 258 memcpy (pluto->fw_rev_str, inq->fw_revision, 4); 259 pluto->fw_rev_str[4] = 0; 260 p = strchr (pluto->fw_rev_str, ' '); 261 if (p) *p = 0; 262 memcpy (pluto->serial_str, inq->serial, 12); 263 pluto->serial_str[12] = 0; 264 p = strchr (pluto->serial_str, ' '); 265 if (p) *p = 0; 266 267 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)) 268 } else 269 fc->fcp_register(fc, TYPE_SCSI_FCP, 1); 270 } else 271 fc->fcp_register(fc, TYPE_SCSI_FCP, 1); 272 } 273 kfree((char *)fcs); 274 if (nplutos) 275 printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos); 276 return nplutos; 277} 278 279int pluto_release(struct Scsi_Host *host) 280{ 281 struct pluto *pluto = (struct pluto *)host->hostdata; 282 fc_channel *fc = pluto->fc; 283 284 module_put(fc->module); 285 286 fc->fcp_register(fc, TYPE_SCSI_FCP, 1); 287 PLND((" releasing pluto.\n")); 288 kfree (fc->ages); 289 PLND(("released pluto!\n")); 290 return 0; 291} 292 293const char *pluto_info(struct Scsi_Host *host) 294{ 295 static char buf[128], *p; 296 struct pluto *pluto = (struct pluto *) host->hostdata; 297 298 sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s", 299 pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, 300 host->max_channel, host->max_id, pluto->fc->name); 301#ifdef __sparc__ 302 p = strchr(buf, 0); 303 sprintf(p, " PROM node %x", pluto->fc->dev->prom_node); 304#endif 305 return buf; 306} 307 308/* SSA uses this FC4S addressing: 309 switch (addr[0]) 310 { 311 case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0 312 case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0 313 case 2: DISK GROUP - ??? 314 } 315 316 So that SCSI mid-layer can access to these, we reserve 317 channel 0 id 0 lun 0 for CONTROLLER 318 and channels 1 .. max_channel are normal single disks. 319 */ 320static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd) 321{ 322 PLND(("encode addr %d %d %d\n", SCpnt->device->channel, SCpnt->device->id, SCpnt->cmnd[1] & 0xe0)) 323 /* We don't support LUNs - neither does SSA :) */ 324 if (SCpnt->cmnd[1] & 0xe0) 325 return -EINVAL; 326 if (!SCpnt->device->channel) { 327 if (SCpnt->device->id) 328 return -EINVAL; 329 memset (addr, 0, 4 * sizeof(u16)); 330 } else { 331 addr[0] = 1; 332 addr[1] = SCpnt->device->channel - 1; 333 addr[2] = SCpnt->device->id; 334 addr[3] = 0; 335 } 336 /* We're Point-to-Point, so target it to the default DID */ 337 fcmd->did = fc->did; 338 PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3])) 339 return 0; 340} 341 342static Scsi_Host_Template driver_template = { 343 .name = "Sparc Storage Array 100/200", 344 .detect = pluto_detect, 345 .release = pluto_release, 346 .info = pluto_info, 347 .queuecommand = fcp_scsi_queuecommand, 348 .slave_configure = pluto_slave_configure, 349 .can_queue = PLUTO_CAN_QUEUE, 350 .this_id = -1, 351 .sg_tablesize = 1, 352 .cmd_per_lun = 1, 353 .use_clustering = ENABLE_CLUSTERING, 354 .eh_abort_handler = fcp_scsi_abort, 355 .eh_device_reset_handler = fcp_scsi_dev_reset, 356 .eh_host_reset_handler = fcp_scsi_host_reset, 357}; 358 359#include "scsi_module.c" 360 361MODULE_LICENSE("GPL"); 362