/* * sn.c -- high-level scsi network driver * * Receives data from upper layers, prepares and send them to the scsi * mid level driver. * * Based on the work of Randy Scott, Chris Frantz and Alan Bork: IP * Encapsulation in SCSI. * * (C) Copyright 2001 Pedro Semeano and Luis Sismeiro * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include /* local development includes */ #include "scsi.h" /* from kernel sources */ #include "hosts.h" /* from kernel sources */ #include "sn.h" int sn_init(void); int sn_detect(Scsi_Device *Sdpnt); int sn_attach(Scsi_Device *sdpnt); void sn_dettach(Scsi_Device *sdpnt); /* static void sn_rx_packet(int size,unsigned char *data); */ struct Scsi_Device_Template sn_template= { name:"scsinet", tag:"sn", blk:1, detect:sn_detect, init:sn_init, finish:NULL, attach:sn_attach, detach:sn_dettach, init_command:NULL, }; static struct sn_upper *sn_upper_devices; struct sn_scsi_device { unsigned int host; unsigned int channel; unsigned int id; unsigned int lun; Scsi_Device *sdpnt; }; static struct sn_scsi_device *devices; long int time; /* FIX ME: is necessary still? */ /*static spinlock_t sn_req_lock = SPIN_LOCK_UNLOCKED; */ static int myid; /* * sn_register_upper * * This function registers the available ??? */ int sn_register_upper(struct sn_upper *dev) { int i; ENTER; dev->next=sn_upper_devices; sn_upper_devices=dev; MOD_INC_USE_COUNT; /* memcpy(dev->snhup.name,dev->name,16); dev->snhup.rx_packet=dev->rx_packet; snh_register_sn(&dev->snhup); */ if (dev->init) { dev->init(); } if (devices!=NULL) { for (i=0;i<16;i+=1) { if (devices[i].sdpnt!=NULL) { if (dev->attach) { dev->attach(i); } } } } EXIT; return 0; } void sn_unregister_upper(struct sn_upper *dev) { struct sn_upper *tmp; struct sn_upper *aux=NULL; int i; ENTER; for (i=0;i<16;i+=1) { if (devices[i].sdpnt!=NULL) if (dev->detach) dev->detach(i); } /* FIX ME */ /* if (sn_upper_devices==NULL) { printk("sn_unregister_upper called without any dev connected\n"); return; }*/ tmp=sn_upper_devices; while (tmp!=dev) { aux=tmp; tmp=tmp->next; if (tmp==NULL) { printk("No such sn_upper device... \n"); return; } } if (aux!=NULL) { aux->next=tmp->next; } else { sn_upper_devices=NULL; } /* snh_unregister_sn(&dev->snhup); */ if (dev->exit) dev->exit(); MOD_DEC_USE_COUNT; EXIT; } int sn_getmyid() { return myid; } /* * sn_attach_upper * * Adds the device to upper layer modules. */ void sn_attach_upper(int dev) { struct sn_upper *ptr; ENTER; for (ptr=sn_upper_devices;ptr!=NULL;ptr=ptr->next) { ptr->attach(dev); } EXIT; } void sn_detach_upper(int dev) { struct sn_upper *ptr; ENTER; for (ptr=sn_upper_devices;ptr!=NULL;ptr=ptr->next) { ptr->detach(dev); } EXIT; } /* * sn_command_done * * This function is called after the scsi_do_req. It frees the allocated * memory for the command buffer and releases the scsi request queu. */ void sn_command_done(Scsi_Cmnd *cmnd) { struct sn_upper *ptr; ENTER; /* Check the command status */ for (ptr=sn_upper_devices;ptr!=NULL;ptr=ptr->next) ptr->tx_finish(cmnd->sc_request->sr_buffer); scsi_release_request(cmnd->sc_request); EXIT; } /* * sn_tx_packet * * int device -> device to send packet * int len -> size of packet * char *data -> data in packet * * Send a packet of data to the SCSI device named. * Uses WRITE10 (the only function we need on the other side). * */ int sn_tx_packet(int num,int len,unsigned char *data) { char cmnd[MAX_COMMAND_SIZE]; Scsi_Request *sn_req=NULL; /* int i; */ ENTER; if (num>=15) { printk("Device does not exist in sn list\n"); return -1; } /* * Beware that snpnt can not be defined (no inquiry before) */ if (devices[num].sdpnt==NULL) { printk("Trying to use a device that is not present...\n"); return -1; } DEBUG(printk("sn: devices[num].sdpnt: %p\n",devices[num].sdpnt)); sn_req=scsi_allocate_request(devices[num].sdpnt); if (sn_req==NULL) { printk("Error allocating memory to scsi_request\n"); return -ENOMEM; } sn_req->sr_data_direction = SCSI_DATA_WRITE; memset(cmnd,0,MAX_COMMAND_SIZE); cmnd[0]=0x2a; cmnd[7]=(len & 0xff00) >> 8; cmnd[8]=(len & 0xff ); scsi_do_req(sn_req,&cmnd,data,len,sn_command_done,HZ,5); EXIT; return 0; } /* * Receives a packet from the lower level driver * Also removes the need for the tasklet. The upper layer must take care of that. * Completely breaks p5.c */ void sn_rx_packet(int size,unsigned char *data) { struct sn_upper *tmp; ENTER; for (tmp=sn_upper_devices;tmp;tmp=tmp->next) { if (tmp->rx_packet(size,data)!=0) { printk("SN: Error sending data to %s\n",tmp->name); } } EXIT; } /* SCSI mid layer functions */ /* * sn_detect * * This function detects the available scsi devices on the bus. It discards * the known ones and try to use the others for target. */ int sn_detect(Scsi_Device *sdpnt) { ENTER; switch (sdpnt->type) { case TYPE_ROM: DEBUG(printk("sn: detected CD-ROM at scsi%d, channel %d, id %d, lun %d. Not using.\n", sdpnt->host->host_no,sdpnt->channel,sdpnt->id,sdpnt->lun)); return 0; case TYPE_WORM: DEBUG(printk("sn: detected WORM at scsi%d, channel %d, id %d, lun %d. Not using.\n", sdpnt->host->host_no,sdpnt->channel,sdpnt->id,sdpnt->lun)); return 0; case TYPE_DISK: DEBUG(printk("sn: detected DISK at scsi%d, channel %d, id %d, lun %d. Not using.\n", sdpnt->host->host_no,sdpnt->channel,sdpnt->id,sdpnt->lun)); return 0; case TYPE_TAPE: DEBUG(printk("sn: detected TAPE at scsi%d, channel %d, id %d, lun %d. Not using.\n", sdpnt->host->host_no,sdpnt->channel,sdpnt->id,sdpnt->lun)); return 0; default: DEBUG(printk("sn: detected something at scsi%d, channel %d, id %d, lun %d. Trying to use it.\n", sdpnt->host->host_no,sdpnt->channel,sdpnt->id,sdpnt->lun)); if (sdpnt->lun==0) sn_template.dev_noticed+=1; } EXIT; return 1; } /* * Prepare the system so that we can send a packet to the devices we detected.. */ int sn_init(void) { ENTER; if (sn_template.dev_noticed==0) return 0; /* * this way we index the devices by id of the device. But we can only use a lun. No more. */ if (devices!=NULL) { kfree(devices); } devices=(struct sn_scsi_device *)kmalloc(sizeof(struct sn_scsi_device)*16,GFP_KERNEL); if (devices==NULL) { printk("SN: No more memory\n"); return -ENOMEM; } memset(devices,0,sizeof(struct sn_scsi_device)*16); EXIT; return 0; } /* * sn_attach * * Attaches the detected scsi devices available for target and call the * function that adds the upper layers. */ int sn_attach(Scsi_Device *sdpnt) { int i=sdpnt->id; ENTER; DEBUG(printk("SN: noticed: %u\n",sn_template.dev_noticed)); devices[i].sdpnt=sdpnt; devices[i].id=i; sn_template.nr_dev++; DEBUG(printk("sn: devices[%u].sdpnt: %p\n",i,devices[i].sdpnt)); DEBUG(printk("SN: Device at %p attached...\n",sdpnt)); sn_attach_upper(i); /* if (sdpnt->host->hostt->module) __MOD_INC_USE_COUNT(sdpnt->host->hostt->module); */ myid=sdpnt->host->this_id; DEBUG(printk("myid=%u\n",myid)); EXIT; return 0; } /* * sn_dettach * * Removes the device from the list of available devices and detaches the scsi device. */ void sn_dettach(Scsi_Device *sdpnt) { int i=sdpnt->id; ENTER; sn_detach_upper(i); DEBUG(printk("SN: Detaching device at %p\n",devices[i].sdpnt)); devices[i].sdpnt=NULL; sdpnt->attached--; sn_template.nr_dev--; sn_template.dev_noticed--; /* if (sdpnt->host->hostt->module) __MOD_DEC_USE_COUNT(sdpnt->host->hostt->module); */ EXIT; } static int __init init_sn(void) { int ret; ENTER; sn_template.module=THIS_MODULE; devices=NULL; ret=scsi_register_module(MODULE_SCSI_DEV,&sn_template); sn_upper_devices=NULL; EXIT; return ret; } static void __exit exit_sn(void) { ENTER; scsi_unregister_module(MODULE_SCSI_DEV,&sn_template); sn_template.dev_max=0; if (devices) kfree(devices); EXIT; } module_init(init_sn); module_exit(exit_sn);