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