diff options
Diffstat (limited to 'release/sysinstall/uc_scsi.c')
| -rw-r--r-- | release/sysinstall/uc_scsi.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/release/sysinstall/uc_scsi.c b/release/sysinstall/uc_scsi.c new file mode 100644 index 0000000000000..2227bb335add6 --- /dev/null +++ b/release/sysinstall/uc_scsi.c @@ -0,0 +1,477 @@ +/*************************************************** + * file: userconfig/uc_scsi.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <nlist.h> +#include <scsi/scsiconf.h> + +#include "uc_main.h" + +/* this stuff is hidden under an #ifdef KERNEL in scsiconf.h */ +#define SCCONF_UNSPEC 255 +#define SCCONF_ANY 254 + +struct scsi_ctlr_config { + int scbus; + char *driver; + int unit; + int bus; +}; + +struct scsi_device_config { + char *name; /* SCSI device name (sd, st, etc) */ + int unit; /* desired device unit */ + int cunit; /* Controller unit */ + int target; /* SCSI ID (target) */ + int lun; /* SCSI lun */ + int flags; /* Flags from config */ +}; + +/* module prototypes */ +static void get_sl_info(struct kernel *kp, struct uc_scsi *spc, + struct scsi_link *sl); + +void +get_scsi_info(struct kernel *kp){ + int i, j, k; + + if(kp->incore){ + if (kp->nl[SCSI_BUSSES].n_value) { + u_int *es, *sba; + struct scsibus_data *sbd; + int nsbd, nscsibus, total; + struct uc_scsi *sp, *spc; + struct uc_scsibus *sbp, *sbpc; + struct scsi_link *s_l; + u_int *slp; + char *temp; + struct scsi_device *sdev; + u_int t; + char name[10]; + + sp=(struct uc_scsi*)malloc(sizeof(struct uc_scsi)); + total=0; + sbp=(struct uc_scsibus*)malloc(sizeof(struct uc_scsibus)); + nscsibus=0; + + es=(u_int *)kv_to_u(kp, kv_dref_p(kp,kp->nl[SCSI_BUSSES].n_value), + sizeof(u_int)*2); + nsbd=es[0]; + sba=(u_int *)kv_to_u(kp, es[1], sizeof(u_int)*nsbd); + free(es); + + for(i=0;i<nsbd;i++){ + if(sba[i]){ + /* first grab the adapter info */ + sbd=(struct scsibus_data *)kv_to_u(kp, sba[i], + sizeof(struct scsibus_data)); + sbp=(struct uc_scsibus *)realloc(sbp, sizeof(struct uc_scsibus)* + (nscsibus+1)); + + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + s_l=(struct scsi_link*)kv_to_u(kp, (u_int)sbd->adapter_link, + sizeof(struct scsi_link)); + get_sl_info(kp, spc, s_l); + free(s_l); + + sbpc=sbp+nscsibus; + sbpc->bus_no=nscsibus; + nscsibus++; + sscanf(spc->device, "%[a-z]%d", name, &sbpc->unit); + asprintf(&sbpc->driver, "%s", name); + + total++; + t=kv_dref_p(kp, (u_int)sbd->sc_link); + t=(u_int)sbd->sc_link; + for(j=0;j<8;j++) { + slp=(u_int *)kv_to_u(kp, t+(j*8*sizeof(u_int)), /* XXX */ + (sizeof(u_int)*sbd->maxlun)); + for(k=0;k<sbd->maxlun && slp[k]; k++){ + struct scsi_link *slt; + sp=(struct uc_scsi*)realloc(sp, + (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + slt=(struct scsi_link*)kv_to_u(kp, slp[k], + sizeof(struct scsi_link)); + get_sl_info(kp, spc, slt); + free(slt); + spc->config=(struct scsi_device_config *)0; + total++; + } + free(slp); + } + free(sbd); + } + } + /* now stuff in the list of drivers configured in the system */ + t=kv_dref_p(kp, kp->nl[SCSI_LIST].n_value); + while(t) { + sdev=(struct scsi_device*)kv_to_u(kp, t, sizeof(struct scsi_device)); + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + total++; + temp=(char *)kv_to_u(kp, (u_int)sdev->name, 10); + asprintf(&spc->device, "%s*", temp); + free(temp); + asprintf(&spc->adapter, "any"); + + spc->target=SCCONF_ANY; + spc->lun=SCCONF_ANY; + + temp=(char *)kv_to_u(kp, (u_int)sdev->desc, 20); + asprintf(&spc->desc, "%s", temp); + free(temp); + + spc->config=(struct scsi_device_config *)0; + + t=(u_int)sdev->next; + free(sdev); + } + /* slap on the terminators */ + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + bzero(spc, sizeof(struct uc_scsi)); + + sbp=(struct uc_scsibus *)realloc(sbp, sizeof(struct uc_scsibus)* + (nscsibus+1)); + sbpc=sbp+nscsibus; + bzero(sbpc, sizeof(struct uc_scsibus)); + + kp->scsi_devp=sp; + kp->scsibus_devp=sbp; + } else { /* no symbol, and incore, no scsi */ + kp->scsi_devp=(struct uc_scsi *)0; + kp->scsibus_devp=(struct uc_scsibus *)0; + } + } else { /* on disk */ + + if (kp->nl[SCSI_CINIT].n_value || kp->nl[SCSI_DINIT].n_value || + kp->nl[SCSI_TINIT].n_value) { + int total=0; + struct uc_scsi *sp, *spc; + struct scsi_ctlr_config *sctl_c; + struct scsi_device_config *sdev_c; + struct scsi_device *sdev; + + struct uc_scsibus *uc_scbus, *uc_scbusc; + + u_int t, ctrl_total; + char *temp; + u_int initp; + + spc=sp=(struct uc_scsi*)malloc(sizeof(struct uc_scsi)); + total=0; + ctrl_total=0; + uc_scbus = NULL; /* Just prevent unused warning */ + + /* static kernel, we'll first get the wired controllers/devices */ + if((t=kp->nl[SCSI_CINIT].n_value)){ + /* get controller info*/ + sctl_c=(struct scsi_ctlr_config*)kv_to_u(kp, t, sizeof(struct scsi_ctlr_config)); + uc_scbus=(struct uc_scsibus*)malloc(sizeof(struct uc_scsibus)); + + while(sctl_c->driver){ + + /* remember the bus info, for later */ + uc_scbus=(struct uc_scsibus*)realloc(uc_scbus, sizeof(struct uc_scsibus)*(ctrl_total+1)); + uc_scbusc=uc_scbus+ctrl_total; + uc_scbusc->bus_no=sctl_c->scbus; + temp=(char *)kv_to_u(kp, (u_int)sctl_c->driver, 20); + uc_scbusc->driver=temp; + uc_scbusc->unit=sctl_c->unit; + uc_scbusc->config=sctl_c; + + sp=(struct uc_scsi*)realloc(sp,sizeof(struct uc_scsi)*(total+1)); + spc=sp+total; + asprintf(&spc->device, "%s%d", temp, sctl_c->unit); + asprintf(&spc->adapter, "%s%d", temp, sctl_c->unit); + spc->target=0; + spc->lun=0; + spc->modified=0; + asprintf(&spc->desc, "%s", temp); + total++; + ctrl_total++; + sctl_c++; + } + } + + if((t=kp->nl[SCSI_DINIT].n_value)){ + /* get wired device info */ + sdev_c=(struct scsi_device_config*)kv_to_u(kp, t, sizeof(struct scsi_device_config)); + while(sdev_c->name){ + sp=(struct uc_scsi*)realloc(sp, sizeof(struct uc_scsi)*(total+1)); + spc=sp+total; + temp=(char*)kv_to_u(kp, (u_int)sdev_c->name, 10); + asprintf(&spc->device, "%s%d", temp, sdev_c->unit); + /* figure out controller */ + if(sdev_c->cunit == SCCONF_ANY){ + asprintf(&spc->adapter, "any"); + } else { + if(ctrl_total){ + for(i=0;i<ctrl_total;i++){ + if(sdev_c->cunit==uc_scbus[i].bus_no){ + asprintf(&spc->adapter, "%s%d", + uc_scbus[i].driver, uc_scbus[i].unit); + break; + } + } + if(i==ctrl_total) { /* made it through the whole list */ + asprintf(&spc->adapter, "any?"); + } + } else { + asprintf(&spc->adapter, "any?"); + } + } + spc->target= sdev_c->target; + spc->lun= sdev_c->lun; + spc->desc=(char *)0; /* filled in later */ + spc->config=sdev_c; + spc->modified=0; + sdev_c++; + total++; + } + } + kp->scsibus_devp=uc_scbus; + + if((t=kp->nl[SCSI_TINIT].n_value)) { + /* WARNING: This is teetering on the brink of stupid. + + this ugly little hack only works because the + <scsi driver>init routines are macro-generated, + so the offset of the device pointers will be + the same (hopefully). + */ + + while((initp=kv_dref_p(kp,t))) { + u_int tadr; + u_int sl; + + t+=4; + tadr=kv_dref_t(kp, initp+4); /* offset in *.text* */ + sdev=(struct scsi_device*)kv_to_u(kp, tadr, sizeof(struct scsi_device)); + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + total++; + temp=(char *)kv_to_u(kp, (u_int)sdev->name, 10); + asprintf(&spc->device, "%s*", temp); + + asprintf(&spc->adapter, "any"); + + spc->target=SCCONF_ANY; + spc->lun=SCCONF_ANY; + spc->modified=0; + temp=(char *)kv_to_u(kp, (u_int)sdev->desc, 20); + asprintf(&spc->desc, "%s", temp); + /* now try to fill in any device descriptions from above */ + sl=strlen(spc->device)-1; + for(i=0;i<(total-1);i++){ /* don't look at this device */ + struct uc_scsi *usp; + + usp=sp+i; + if(strncmp(usp->device, spc->device, sl)==0 && usp->desc==0) { + asprintf(&usp->desc, "%s", spc->desc); + } + } + } + if(total){ + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + bzero(spc, sizeof(struct uc_scsi)); + kp->scsi_devp=sp; + } else { + free(sp); + kp->scsi_devp=(struct uc_scsi *)0; + } + } + } else { + kp->scsi_devp=(struct uc_scsi *)0; + } + } +} + +struct list * +get_scsi_devlist(struct kernel *kp){ + struct list *dl; + struct uc_scsi *kdp; + + dl=list_new(); + + for(kdp=kp->scsi_devp; kdp->device; kdp++){ + list_append(dl, kdp->device); + } + + return(dl); +} + +struct list * +get_scsi_device(struct uc_scsi *sp){ + struct list *list; + char *tmp; + + list=list_new(); + + list_append(list, sp->device); + list_append(list, sp->adapter); + + asprintf(&tmp, "%d", sp->target ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", sp->lun ); + list_append(list, tmp); + free(tmp); + + list_append(list, sp->desc); + + return(list); +} + +/* given a scsi_link and a uc_scsi pointer, fill it in */ +static void +get_sl_info(struct kernel *kp, struct uc_scsi *spc, struct scsi_link *sl){ + + struct scsi_adapter *sadp; + struct scsi_device *sdev; + char *temp; + + sadp=(struct scsi_adapter*)kv_to_u(kp, (u_int)sl->adapter, + sizeof(struct scsi_adapter)); + + sdev=(struct scsi_device*)kv_to_u(kp, (u_int)sl->device, + sizeof(struct scsi_device)); + + temp=(char *)kv_to_u(kp, (u_int)sdev->name, 20); + asprintf(&spc->device, "%s%d", temp, sl->dev_unit); + free(temp); + temp=(char *)kv_to_u(kp, (u_int)sadp->name, 20); + asprintf(&spc->adapter, "%s%d", temp, sl->adapter_unit); + free(temp); + spc->target = sl->target; + spc->lun = sl->lun; + + temp=(char *)kv_to_u(kp, (u_int)sdev->desc, 30); + asprintf(&spc->desc, "%s", temp); + free(temp); + +} + +int +scsi_setdev(struct kernel *kp, struct list *list){ + int r=1, bus_valid=0; + struct uc_scsi *sp; + struct uc_scsibus *sbp; + char *t; + + if(kp->scsi_devp) + for(sp=kp->scsi_devp;sp->device;sp++){ + if(strcmp(list->av[0], sp->device)==0){ + for(sbp=kp->scsibus_devp;sbp->driver; sbp++){ + asprintf(&t, "%s%d", sbp->driver, sbp->unit); + if(strcmp(list->av[1], t)==0) { + bus_valid=1; + } + free(t); + } + if(bus_valid){ + sp->modified=1; + free(sp->adapter); + asprintf(&sp->adapter, "%s", list->av[1]); + sp->target = strtol(list->av[2], (char **)NULL, 0); + sp->lun = strtol(list->av[3], (char **)NULL, 0); + r=0; + goto done; + } else { + r=2; + } + } + } +done: + return(r); +} + +void +scsi_free(struct kernel *kp, int writeback){ + struct uc_scsi *sp; + struct uc_scsibus *sbp; + char *t; + int scbus, i; + + for(sp=kp->scsi_devp; sp->device; sp++){ + if((!kp->incore) && sp->modified && writeback) { + /* save info */ + + /* I'm not sure this is necessary */ +#if 0 + sscanf(sp->device, "%[a-z]%d", name, &unit); + sp->config->unit= unit; +#endif + + /* figger out the controller, which may have changed */ + scbus=-1; + for(sbp=kp->scsibus_devp, i=0;sbp->driver; sbp++,i++){ + asprintf(&t, "%s%d", sbp->driver, sbp->unit); + if(strcmp(sp->adapter, t)==0) { + scbus=i; + } + free(t); + } + + /* if we fell through, don't change anything */ + if(scbus!=-1){ + sp->config->cunit= scbus; + } + + sp->config->target= sp->target; + sp->config->lun= sp->lun; + /* sp->config->flags= ; XXX this should be here*/ + + } + free(sp->device); + free(sp->adapter); + free(sp->desc); + } + free(kp->scsi_devp); + kp->scsi_devp=(struct uc_scsi *)0; + /* now free the bus info */ + if(kp->incore){ + for(sbp=kp->scsibus_devp;sbp->driver; sbp++){ +/* fprintf(stderr, "sbp: 0x%x free(0x%x)\n", sbp, sbp->driver);*/ + free(sbp->driver); + } + } + + if (kp->scsibus_devp) + free(kp->scsibus_devp); + kp->scsibus_devp=(struct uc_scsibus *)0; +} + +/* end of userconfig/uc_scsi.c */ |
