# Makefile for the Linux iSCSI driver
# Copyright (C) 2001 Cisco Systems, Inc.
# maintained by linux-iscsi@cisco.com
#
# 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.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# See the file COPYING included with this distribution for more details.

OS:=$(shell uname)
ARCH:=$(shell uname -m)

ifeq ($(OS),SunOS)

CC=gcc
CFLAGS = -Wall -Wstrict-prototypes -O2 -DSOLARIS
LDFLAGS=-lnsl -lsocket

else

# assume it's Linux

# Where to install files that must be relative to the root dir.
# This is a prefix prepended before the pathname, and is
# normally unset.  It would be set for such things as diskless
# clients, where the driver is being installed on the server
# for a client.
ROOT:=
export ROOT

# Where to install the relocatable files (daemon, utilities, and man pages)
BASEDIR:=/usr/local
export BASEDIR

# We need to have the kernel headers installed in order to compile.
# You can specify a TOPDIR for your Linux kernel here, or if you don't
# we'll probe a few likely places next
TOPDIR:=

# record the version of the running kernel
KERNEL_VPSE:=$(shell uname -r)
KERNEL_VPS:=$(shell uname -r | sed -e 's|^\([0-9]\+\.[0-9]\+\.[0-9]\+\).*|\1|')
KERNEL_VP:=$(shell uname -r | awk -F. '{ print $$1 "." $$2}')

ifeq ($(TOPDIR),)
# Try to find the top of the Linux kernel source tree for the running kernel
ifeq ($(wildcard /usr/src/linux/.),/usr/src/linux/.)
TOPDIR:=/usr/src/linux
endif
# linux-v.p
ifeq ($(wildcard /usr/src/linux-$(KERNEL_VP)/.),/usr/src/linux-$(KERNEL_VP)/.)
TOPDIR:=/usr/src/linux-$(KERNEL_VP)
endif
# linux-v.p.s
ifeq ($(wildcard /usr/src/linux-$(KERNEL_VPS)/.),/usr/src/linux-$(KERNEL_VPS)/.)
TOPDIR:=/usr/src/linux-$(KERNEL_VPS)
endif
# linux-v.p.s-e
ifeq ($(wildcard /usr/src/linux-$(KERNEL_VPSE)/.),/usr/src/linux-$(KERNEL_VPSE)/.)
TOPDIR:=/usr/src/linux-$(KERNEL_VPSE)
endif
# Linus has recommended a symlink /lib/modules/`uname -r`/build
ifeq ($(wildcard /lib/modules/$(KERNEL_VPSE)/build/.),/lib/modules/$(KERNEL_VPSE)/build/.)
TOPDIR:=/lib/modules/$(KERNEL_VPSE)/build
endif
ifeq ($(TOPDIR),)
$(warning Linux kernel source must be installed to compile this code.)
$(error Could not find the top of the linux kernel source tree.)
endif
endif

# the kernel source version
KERNEL_VERSION:=$(shell awk -F"[ \t]*=[ \t]*" '$$1 == "VERSION" { print $$2 }' $(TOPDIR)/Makefile | sed -e 's/[ \t\n]*//g')
KERNEL_PATCHLEVEL:=$(shell awk -F"[ \t]*=[ \t]*" '$$1 == "PATCHLEVEL" {print $$2 }' $(TOPDIR)/Makefile | sed -e 's/[ \t\n]*//g')
KERNEL_SUBLEVEL:=$(shell awk -F"[ \t]*=[ \t]*" '$$1 == "SUBLEVEL" {print $$2 }' $(TOPDIR)/Makefile | sed -e 's/[ \t\n]*//g')
KERNEL_EXTRAVERSION:=$(shell awk -F"[ \t]*=[ \t]*" '$$1 == "EXTRAVERSION" {print $$2 }' $(TOPDIR)/Makefile | sed -e 's/[ \t\n]*//g')
KERNEL_SRC_VPS:=$(KERNEL_VERSION).$(KERNEL_PATCHLEVEL).$(KERNEL_SUBLEVEL)
KERNEL_SRC_VPSE:=$(KERNEL_VERSION).$(KERNEL_PATCHLEVEL).$(KERNEL_SUBLEVEL)$(KERNEL_EXTRAVERSION)

CC:=gcc
KERNELCC:=gcc
CFLAGS:= -Wall -Wstrict-prototypes -O2 -DLINUX
LDFLAGS:=
MODFLAGS:=-D__KERNEL__=1 -DMODULE -I$(TOPDIR)/include -I$(TOPDIR)/drivers/scsi
MODVERFLAGS:=-DMODVERSIONS -include $(TOPDIR)/include/linux/modversions.h

# FIXME:  using -include puts an absolute filename in the dependency files,
# which can cause needless recompiles after kernel upgrades.  Either
# switch to a normal include in the .c files, or find another way to tell
# gcc to include the modversions file from the command line

ifdef DEBUG
OBJDIR=$(OS)-$(ARCH)-dbg/obj
KOBJDIR=$(OS)-$(ARCH)-dbg/kobj
CLEANDIRS:=$(OS)-$(ARCH)/obj $(OS)-$(ARCH)/kobj
CFLAGS += -g -DDEBUG
LDFLAGS += -g
MODFLAGS += -DDEBUG
else
OBJDIR:=$(OS)-$(ARCH)/obj
KOBJDIR:=$(OS)-$(ARCH)/kobj
CLEANDIRS:=$(OS)-$(ARCH)-dbg/obj $(OS)-$(ARCH)-dbg/kobj
CFLAGS += -fomit-frame-pointer  
endif

endif # OS

export OBJDIR
export KOBJDIR

.PHONY: all module daemons utils tools kernel user permissions clean tar dist release \
         checklocal version newversion install remove uninstall dirs warnguess

# default target
all:: dirs checkkernel checkscsi module daemons utils tools permissions

module: warnguess dirs $(KOBJDIR)/iscsi_mod.o
daemons:  dirs $(OBJDIR)/iscsid
utils: dirs $(OBJDIR)/iscsi-device $(OBJDIR)/iscsi-iname 
# 
obsolete:  $(OBJDIR)/iscsilun 
daemon2:  dirs $(OBJDIR)/iscsidd
test: dirs $(OBJDIR)/bindings

tools: dirs $(OBJDIR)/iscsigt
	@cp -f $(OBJDIR)/iscsigt iscsigt

# distributors usually want these targets when building packages
user: dirs daemons utils
kernel: dirs module

# Check the kernel's config
ifeq ($(wildcard $(TOPDIR)/.config),$(TOPDIR)/.config)

include $(TOPDIR)/.config

SCSI=no
ifdef CONFIG_SCSI
ifeq ($(CONFIG_SCSI),m)
	SCSI=module
endif
ifeq ($(CONFIG_SCSI),y)
	SCSI=yes
endif
endif

# multi-processor kernel?
SMP=no
ifdef CONFIG_SMP
ifeq ($(CONFIG_SMP),y)
	SMP=yes
	MODFLAGS += -D__SMP__
endif
endif

# check if modversions is being used
MODVERSIONS=no
ifdef CONFIG_MODVERSIONS
ifeq ($(CONFIG_MODVERSIONS),y)
MODFLAGS += $(MODVERFLAGS)
MODVERSIONS=yes
endif
endif

else

# No .config to tell us about CONFIG_SMP
# guess based on the uname output
ifeq (SMP, $(findstring SMP, $(shell uname -v)))
SMP=guess-yes
MODFLAGS += -D__SMP__
else
SMP=guess-no
endif

# No .config to tell us about MODVERSIONS
# Check /proc/ksyms to see if it looks like modversions are in use
# We need to find a symbol that will always be compiled in, regardless
# of the kernel config.
MODVERSIONS=$(shell awk '$$2 ~ /^kmalloc$$/ { print "guess-no" } ; $$2 ~ /^kmalloc_R/ { print "guess-yes" }' /proc/ksyms)
ifeq ($(MODVERSIONS),guess-yes)
MODFLAGS+=$(MODVERFLAGS)
endif

SCSI=maybe

endif

.SUFFIXES:

MODULE_SRCS:=iscsi.c iscsi-probe.c iscsi-login.c iscsiAuthClient.c iscsiAuthClientGlue.c md5.c 
DAEMON_SRCS:=iscsid.c iscsiAuthClient.c iscsiAuthClientGlue.c md5.c
DAEMON2_SRCS:=iscsidd.c iscsi-linux.c iscsi-login.c iscsi-io.c iscsi-config.c iscsi-discovery.c iscsi-bindings.c \
	       iscsiAuthClient.c iscsiAuthClientGlue.c md5.c
UTIL_SRCS:=iscsi-iname.c md5.c iscsi-device.c iscsigt.c

MODULE_OBJS:=$(MODULE_SRCS:%.c=$(KOBJDIR)/%.o)
DAEMON_OBJS:=$(DAEMON_SRCS:%.c=$(OBJDIR)/%.o) $(OBJDIR)/textkey.o
DAEMON2_OBJS:=$(DAEMON2_SRCS:%.c=$(OBJDIR)/%.o)
UTIL_OBJS:=$(UTIL_SRCS:%.c=$(OBJDIR)/%.o)

# pull in autodeps for module objects that already exist
-include $(MODULE_SRCS:%.c=$(KOBJDIR)/%.dep)

# compile kernel module code and auto-generate dependencies (and make missing prereqs cause a rebuild, not an error)
$(KOBJDIR)/%.o : %.c
	@mkdir -p $(KOBJDIR)
	$(KERNELCC) $(CFLAGS) $(MODFLAGS) -MMD -c -o $(KOBJDIR)/$*.o $*.c
	@if [ ! -f $(KOBJDIR)/$*.d -a -f $*.d ] ; then \
		echo -n "$(KOBJDIR)/" > $(KOBJDIR)/$*.d ; \
		cat $*.d >> $(KOBJDIR)/$*.d && rm -f $*.d ; \
        fi
	@cp -f $(KOBJDIR)/$*.d $(KOBJDIR)/$*.dep
	@sed -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' -e 's/^ *//' -e '/^$$/ d' -e 's/$$/:/' < $(KOBJDIR)/$*.d >> $(KOBJDIR)/$*.dep

# pull in autodeps for daemon and utility objects that already exist
-include $(DAEMON_SRCS:%.c=$(OBJDIR)/%.dep)

# compile daemon/utility code and auto-generate dependencies (and make missing prereqs cause a rebuild, not an error)
$(OBJDIR)/%.o : %.c
	@mkdir -p $(OBJDIR)
	$(CC) $(CFLAGS) $(DAEMONFLAGS) -MMD -c -o $(OBJDIR)/$*.o $*.c
	@if [ ! -f $(OBJDIR)/$*.d -a -f $*.d ] ; then \
		echo -n "$(OBJDIR)/" > $(OBJDIR)/$*.d ; \
		cat $*.d >> $(OBJDIR)/$*.d && rm -f $*.d ; \
        fi
	@cp -f $(OBJDIR)/$*.d $(OBJDIR)/$*.dep
	@sed -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' -e 's/^ *//' -e '/^$$/ d' -e 's/$$/:/' < $(OBJDIR)/$*.d >> $(OBJDIR)/$*.dep

# Make all objects depend on the Makefile
$(MODULE_OBJS): Makefile
$(DAEMON_OBJS): Makefile
$(DAEMON2_OBJS): Makefile
$(UTIL_OBJS): Makefile

install: module daemons utils
	@./install.sh

remove uninstall: 
	@./remove.sh 


# warn the user if the running kernel version 
# doesn't match the $TOPDIR/Makefile version
# a Redhat 7.1 beta installed on an SMP box will run 2.4.2-2smp, but have source for 2.4.1,
# which doesn't work.
checkkernel:
	@if [ "$(KERNEL_VERSION).$(KERNEL_PATCHLEVEL)" = "2.2" -a $(KERNEL_SUBLEVEL) -lt 16 ] ; then \
		echo "" ; \
		echo "Error: this iSCSI driver requires kernel 2.2.16 or later." ; \
		echo "" ; \
		exit 1; \
	fi 
	@if [ "$(KERNEL_SRC_VPS)" -a "$(KERNEL_VPS)" -a "$(KERNEL_SRC_VPS)" != "$(KERNEL_VPS)" ] ; then \
		echo "" ; \
		echo "Warning: $(TOPDIR) contains kernel version $(KERNEL_SRC_VPS)," ; \
		echo "         but kernel version $(KERNEL_VPS) is currently running."; \
		echo "         This mismatch may prevent the iscsi module from loading"; \
		echo "         due to unresolved symbols, or may cause problems during the operation"; \
		echo "         of the iSCSI driver.  It is strongly recommended that you install the"; \
		echo "         kernel source for version $(KERNEL_VPSE), and rebuild the iSCSI driver."; \
		echo "" ; \
	fi;

# Error out if there is no scsi support in the kernel
checkscsi:
	@if [ "$(SCSI)" = "no" ] ; then \
		echo ; \
		echo "Error: your kernel does not support SCSI." ; \
		echo "For iSCSI to function, you must rebuild your kernel with either" ; \
		echo "SCSI support compiled into the kernel, or with SCSI support as a module." ; \
		echo ; \
		exit 1;\
	fi

# kernel module
warnguess:
	@case "$(MODVERSIONS)" in \
	guess-yes) \
		echo "" ; \
		echo "Warning: $(TOPDIR)/.config doesn't exist," ; \
		echo "so we can't check CONFIG_MODVERSIONS." ; \
		echo "However, a look at /proc/ksyms suggests that" ; \
		echo "your kernel is compiled with modversions." ; \
		echo "We'll assume your running kernel matches $(TOPDIR)," ; \
		echo "and compile the iSCSI kernel module with modversions." ;\
		echo "" ; \
		;; \
	guess-no) \
		echo "" ; \
		echo "Warning: $(TOPDIR)/.config doesn't exist," ; \
		echo "so we can't check CONFIG_MODVERSIONS." ; \
		echo "However, a look at /proc/ksyms suggests that" ; \
		echo "your kernel is compiled without modversions." ; \
		echo "We'll assume your running kernel matches $(TOPDIR)," ; \
		echo "and compile the iSCSI kernel module without modversions." ;\
		echo "" ; \
		;; \
	*) : ;; \
	esac
	@case "$(SMP)" in \
	guess-yes) \
		echo "" ; \
		echo "Warning: $(TOPDIR)/.config doesn't exist," ; \
		echo "so we can't check CONFIG_SMP." ; \
		echo "Based on the uname output, we're guessing that" ;\
		echo "your kernel is built with SMP enabled, and" ;\
		echo "we'll compile the iSCSI kernel module with -D__SMP__"; \
		echo "to create a module suitable for use with multiprocessors.";\
		echo "" ; \
		;; \
	guess-no) \
		echo "" ; \
		echo "Warning: $(TOPDIR)/.config doesn't exist," ; \
		echo "so we can't check CONFIG_SMP." ; \
		echo "Based on the uname output, we're guessing that" ;\
		echo "your kernel is built with SMP disabled, and" ;\
		echo "we'll compile the iSCSI kernel module for a uniprocessor."; \
		echo "" ; \
		;; \
	*) : ;; \
	esac

# link the iSCSI kernel module
$(KOBJDIR)/iscsi_mod.o: $(MODULE_OBJS)
	$(LD) -r -o $@ $^

$(OBJDIR)/textkey.o: textkey.cpp textkey.hpp
	g++ -c $(CFLAGS) -o $@ $<

# need a special rule to handle the C++ textkey stuff
$(OBJDIR)/iscsid.o: iscsid.c iscsid.h iscsi-protocol.h iscsi-ioctl.h iscsi-common.h iscsi-trace.h \
	  iscsiAuthClient.h iscsiAuthClientGlue.h iscsi-version.h  Makefile
	g++ $(CFLAGS) $(DAEMONFLAGS) -c -o $@ $<

# link the iSCSI daemon
$(OBJDIR)/iscsid: $(DAEMON_OBJS)
	g++ $(LDFLAGS) $(DAEMONFLAGS) -o $@ $^

# link the new iSCSI daemon
$(OBJDIR)/iscsidd: $(DAEMON2_OBJS)
	$(CC) $(LDFLAGS) $(DAEMONFLAGS) -o $@ $^

# includes TOPDIR/include/scsi/scsi_ioctl.h
$(OBJDIR)/iscsi-device: iscsi-device.c Makefile
	$(CC) $(CFLAGS) -I$(TOPDIR)/include -o $@ $<

# Link the iscsi-iname utility
$(OBJDIR)/iscsi-iname: $(OBJDIR)/iscsi-iname.o $(OBJDIR)/md5.o
	$(CC) $(CFLAGS) -o $@ $^

# development get trace utility
$(OBJDIR)/iscsigt: $(OBJDIR)/iscsigt.o
	$(CC) $(CFLAGS) -o $@ $<

# test binding code
$(OBJDIR)/bindings.o: iscsi-bindings.c iscsi-bindings.h iscsidd.h iscsi-config.h iscsi-platform.h iscsi-daemon.h
	$(CC) $(CFLAGS) -DTEST -c -o $@ $<

# test binding code
$(OBJDIR)/bindings: $(OBJDIR)/bindings.o $(OBJDIR)/iscsi-config.o $(OBJDIR)/iscsi-linux.o
	$(CC) $(CFLAGS) -o $@ $^

# obsolete lun activation utility
$(OBJDIR)/iscsilun: iscsilun.c iscsid.h iscsi-common.h iscsi-protocol.h Makefile
	$(CC) $(CFLAGS) -o $@ $<

dirs:
	@mkdir -p $(OBJDIR)
	@mkdir -p $(KOBJDIR)

permissions:
	@chmod a+x rc.iscsi
	@chmod a+x install.sh
	@chmod a+x remove.sh
	@chmod a+x upgrade.sh
	@chmod a+x iscsi-mountall
	@chmod a+x iscsi-umountall

clean:
	rm -rf $(OBJDIR) $(KOBJDIR) $(CLEANDIRS) *.o *.d *.dep


